to send simple function calls to the server.
</para>
- <tip>
+ <warning>
<para>
- This interface is somewhat obsolete, as one can achieve similar
+ This interface is unsafe and should not be used. When
+ <parameter>result_is_int</parameter> is set to <literal>0</literal>,
+ <function>PQfn</function> may write data beyond the end of
+ <parameter>result_buf</parameter>, regardless of whether the buffer has
+ enough space for the requested number of bytes. Furthermore, it is
+ obsolete, as one can achieve similar
performance and greater functionality by setting up a prepared
statement to define the function call. Then, executing the statement
with binary transmission of parameters and results substitutes for a
fast-path function call.
</para>
- </tip>
+ </warning>
<para>
The function <function id="libpq-PQfn">PQfn</function><indexterm><primary>PQfn</primary></indexterm>
int result_is_int,
const PQArgBlock *args,
int nargs)
+{
+ return PQnfn(conn, fnid, result_buf, -1, result_len,
+ result_is_int, args, nargs);
+}
+
+/*
+ * PQnfn
+ * Private version of PQfn() with verification that returned data fits in
+ * result_buf when result_is_int == 0. Setting buf_size to -1 disables
+ * this verification.
+ */
+PGresult *
+PQnfn(PGconn *conn, int fnid, int *result_buf, int buf_size, int *result_len,
+ int result_is_int, const PQArgBlock *args, int nargs)
{
*result_len = 0;
}
return pqFunctionCall3(conn, fnid,
- result_buf, result_len,
+ result_buf, buf_size, result_len,
result_is_int,
args, nargs);
}
argv[1].len = 4;
argv[1].u.integer = (int) len;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
- (void *) buf, &result_len, 0, argv, 2);
+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_read,
+ (void *) buf, len, &result_len, 0, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
argv[2].len = 4;
argv[2].u.integer = whence;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64,
- (void *) &retval, &result_len, 0, argv, 3);
+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek64,
+ (void *) &retval, sizeof(retval), &result_len, 0, argv, 3);
if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
{
PQclear(res);
argv[0].len = 4;
argv[0].u.integer = fd;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64,
- (void *) &retval, &result_len, 0, argv, 1);
+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_tell64,
+ (void *) &retval, sizeof(retval), &result_len, 0, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
{
PQclear(res);
*/
PGresult *
pqFunctionCall3(PGconn *conn, Oid fnid,
- int *result_buf, int *actual_result_len,
+ int *result_buf, int buf_size, int *actual_result_len,
int result_is_int,
const PQArgBlock *args, int nargs)
{
}
else
{
+ /*
+ * If the server returned too much data for the
+ * buffer, something fishy is going on. Abandon ship.
+ */
+ if (buf_size != -1 && *actual_result_len > buf_size)
+ {
+ libpq_append_conn_error(conn, "server returned too much data");
+ handleFatalError(conn);
+ return pqPrepareAsyncResult(conn);
+ }
+
if (pqGetnchar(result_buf,
*actual_result_len,
conn))
extern void pqCommandQueueAdvance(PGconn *conn, bool isReadyForQuery,
bool gotSync);
extern int PQsendQueryContinue(PGconn *conn, const char *query);
+extern PGresult *PQnfn(PGconn *conn, int fnid, int *result_buf, int buf_size,
+ int *result_len, int result_is_int,
+ const PQArgBlock *args, int nargs);
/* === in fe-protocol3.c === */
extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize);
extern int pqEndcopy3(PGconn *conn);
extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid,
- int *result_buf, int *actual_result_len,
+ int *result_buf, int buf_size,
+ int *actual_result_len,
int result_is_int,
const PQArgBlock *args, int nargs);