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