Thread

  1. [PATCH v1 3/3] LO frontend PQexecParams

    Nathan Bossart <nathan@postgresql.org> — 2026-05-26T16:12:49Z

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