PostgreSQL Source Code git master
libpq-be-fe-helpers.h File Reference
#include "libpq-fe.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "storage/latch.h"
#include "utils/timestamp.h"
#include "utils/wait_event.h"
Include dependency graph for libpq-be-fe-helpers.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

static void libpqsrv_connect_prepare (void)
 
static void libpqsrv_connect_internal (PGconn *conn, uint32 wait_event_info)
 
static PGresultlibpqsrv_get_result_last (PGconn *conn, uint32 wait_event_info)
 
static PGresultlibpqsrv_get_result (PGconn *conn, uint32 wait_event_info)
 
static PGconnlibpqsrv_connect (const char *conninfo, uint32 wait_event_info)
 
static PGconnlibpqsrv_connect_params (const char *const *keywords, const char *const *values, int expand_dbname, uint32 wait_event_info)
 
static void libpqsrv_disconnect (PGconn *conn)
 
static PGresultlibpqsrv_exec (PGconn *conn, const char *query, uint32 wait_event_info)
 
static PGresultlibpqsrv_exec_params (PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat, uint32 wait_event_info)
 
static const char * libpqsrv_cancel (PGconn *conn, TimestampTz endtime)
 

Function Documentation

◆ libpqsrv_cancel()

static const char * libpqsrv_cancel ( PGconn conn,
TimestampTz  endtime 
)
inlinestatic

Definition at line 386 of file libpq-be-fe-helpers.h.

387{
388 PGcancelConn *cancel_conn;
389 const char *error = NULL;
390
391 cancel_conn = PQcancelCreate(conn);
392 if (cancel_conn == NULL)
393 return "out of memory";
394
395 /* In what follows, do not leak any PGcancelConn on any errors. */
396
397 PG_TRY();
398 {
399 if (!PQcancelStart(cancel_conn))
400 {
401 error = pchomp(PQcancelErrorMessage(cancel_conn));
402 goto exit;
403 }
404
405 for (;;)
406 {
409 long cur_timeout;
410 int waitEvents = WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH;
411
412 pollres = PQcancelPoll(cancel_conn);
413 if (pollres == PGRES_POLLING_OK)
414 break; /* success! */
415
416 /* If timeout has expired, give up, else get sleep time. */
418 cur_timeout = TimestampDifferenceMilliseconds(now, endtime);
419 if (cur_timeout <= 0)
420 {
421 error = "cancel request timed out";
422 break;
423 }
424
425 switch (pollres)
426 {
428 waitEvents |= WL_SOCKET_READABLE;
429 break;
431 waitEvents |= WL_SOCKET_WRITEABLE;
432 break;
433 default:
434 error = pchomp(PQcancelErrorMessage(cancel_conn));
435 goto exit;
436 }
437
438 /* Sleep until there's something to do */
439 WaitLatchOrSocket(MyLatch, waitEvents, PQcancelSocket(cancel_conn),
440 cur_timeout, PG_WAIT_CLIENT);
441
443
445 }
446exit: ;
447 }
448 PG_FINALLY();
449 {
450 PQcancelFinish(cancel_conn);
451 }
452 PG_END_TRY();
453
454 return error;
455}
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition: timestamp.c:1756
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1644
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1608
int64 TimestampTz
Definition: timestamp.h:39
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_FINALLY(...)
Definition: elog.h:388
PGcancelConn * PQcancelCreate(PGconn *conn)
Definition: fe-cancel.c:65
PostgresPollingStatusType PQcancelPoll(PGcancelConn *cancelConn)
Definition: fe-cancel.c:207
void PQcancelFinish(PGcancelConn *cancelConn)
Definition: fe-cancel.c:334
int PQcancelSocket(const PGcancelConn *cancelConn)
Definition: fe-cancel.c:294
char * PQcancelErrorMessage(const PGcancelConn *cancelConn)
Definition: fe-cancel.c:306
int PQcancelStart(PGcancelConn *cancelConn)
Definition: fe-cancel.c:185
struct Latch * MyLatch
Definition: globals.c:62
int WaitLatchOrSocket(Latch *latch, int wakeEvents, pgsocket sock, long timeout, uint32 wait_event_info)
Definition: latch.c:565
void ResetLatch(Latch *latch)
Definition: latch.c:724
#define WL_SOCKET_READABLE
Definition: latch.h:128
#define WL_TIMEOUT
Definition: latch.h:130
#define WL_EXIT_ON_PM_DEATH
Definition: latch.h:132
#define WL_LATCH_SET
Definition: latch.h:127
#define WL_SOCKET_WRITEABLE
Definition: latch.h:129
PostgresPollingStatusType
Definition: libpq-fe.h:111
@ PGRES_POLLING_OK
Definition: libpq-fe.h:115
@ PGRES_POLLING_READING
Definition: libpq-fe.h:113
@ PGRES_POLLING_WRITING
Definition: libpq-fe.h:114
exit(1)
char * pchomp(const char *in)
Definition: mcxt.c:1724
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static void error(void)
Definition: sql-dyntest.c:147
PGconn * conn
Definition: streamutil.c:53
#define PG_WAIT_CLIENT
Definition: wait_event.h:22

References CHECK_FOR_INTERRUPTS, conn, error(), exit(), GetCurrentTimestamp(), MyLatch, now(), pchomp(), PG_END_TRY, PG_FINALLY, PG_TRY, PG_WAIT_CLIENT, PGRES_POLLING_OK, PGRES_POLLING_READING, PGRES_POLLING_WRITING, PQcancelCreate(), PQcancelErrorMessage(), PQcancelFinish(), PQcancelPoll(), PQcancelSocket(), PQcancelStart(), ResetLatch(), TimestampDifferenceMilliseconds(), WaitLatchOrSocket(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, WL_SOCKET_READABLE, WL_SOCKET_WRITEABLE, and WL_TIMEOUT.

Referenced by dblink_cancel_query(), pgfdw_cancel_query_begin(), and pgfdw_get_cleanup_result().

◆ libpqsrv_connect()

static PGconn * libpqsrv_connect ( const char *  conninfo,
uint32  wait_event_info 
)
inlinestatic

Definition at line 66 of file libpq-be-fe-helpers.h.

67{
68 PGconn *conn = NULL;
69
71
72 conn = PQconnectStart(conninfo);
73
74 libpqsrv_connect_internal(conn, wait_event_info);
75
76 return conn;
77}
PGconn * PQconnectStart(const char *conninfo)
Definition: fe-connect.c:900
static void libpqsrv_connect_prepare(void)
static void libpqsrv_connect_internal(PGconn *conn, uint32 wait_event_info)

References conn, libpqsrv_connect_internal(), libpqsrv_connect_prepare(), and PQconnectStart().

Referenced by dblink_connect(), and dblink_get_conn().

◆ libpqsrv_connect_internal()

static void libpqsrv_connect_internal ( PGconn conn,
uint32  wait_event_info 
)
inlinestatic

Definition at line 160 of file libpq-be-fe-helpers.h.

161{
162 /*
163 * With conn == NULL libpqsrv_disconnect() wouldn't release the FD. So do
164 * that here.
165 */
166 if (conn == NULL)
167 {
169 return;
170 }
171
172 /*
173 * Can't wait without a socket. Note that we don't want to close the libpq
174 * connection yet, so callers can emit a useful error.
175 */
177 return;
178
179 /*
180 * WaitLatchOrSocket() can conceivably fail, handle that case here instead
181 * of requiring all callers to do so.
182 */
183 PG_TRY();
184 {
186
187 /*
188 * Poll connection until we have OK or FAILED status.
189 *
190 * Per spec for PQconnectPoll, first wait till socket is write-ready.
191 */
192 status = PGRES_POLLING_WRITING;
193 while (status != PGRES_POLLING_OK && status != PGRES_POLLING_FAILED)
194 {
195 int io_flag;
196 int rc;
197
198 if (status == PGRES_POLLING_READING)
199 io_flag = WL_SOCKET_READABLE;
200#ifdef WIN32
201
202 /*
203 * Windows needs a different test while waiting for
204 * connection-made
205 */
206 else if (PQstatus(conn) == CONNECTION_STARTED)
207 io_flag = WL_SOCKET_CONNECTED;
208#endif
209 else
210 io_flag = WL_SOCKET_WRITEABLE;
211
214 PQsocket(conn),
215 0,
216 wait_event_info);
217
218 /* Interrupted? */
219 if (rc & WL_LATCH_SET)
220 {
223 }
224
225 /* If socket is ready, advance the libpq state machine */
226 if (rc & io_flag)
227 status = PQconnectPoll(conn);
228 }
229 }
230 PG_CATCH();
231 {
232 /*
233 * If an error is thrown here, the callers won't call
234 * libpqsrv_disconnect() with a conn, so release resources
235 * immediately.
236 */
238 PQfinish(conn);
239
240 PG_RE_THROW();
241 }
242 PG_END_TRY();
243}
#define PG_RE_THROW()
Definition: elog.h:412
#define PG_CATCH(...)
Definition: elog.h:381
void ReleaseExternalFD(void)
Definition: fd.c:1238
PostgresPollingStatusType PQconnectPoll(PGconn *conn)
Definition: fe-connect.c:2818
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7444
void PQfinish(PGconn *conn)
Definition: fe-connect.c:5178
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:7533
#define WL_SOCKET_CONNECTED
Definition: latch.h:137
@ CONNECTION_STARTED
Definition: libpq-fe.h:89
@ CONNECTION_BAD
Definition: libpq-fe.h:82
@ PGRES_POLLING_FAILED
Definition: libpq-fe.h:112

References CHECK_FOR_INTERRUPTS, conn, CONNECTION_BAD, CONNECTION_STARTED, MyLatch, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PGRES_POLLING_FAILED, PGRES_POLLING_OK, PGRES_POLLING_READING, PGRES_POLLING_WRITING, PQconnectPoll(), PQfinish(), PQsocket(), PQstatus(), ReleaseExternalFD(), ResetLatch(), WaitLatchOrSocket(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, WL_SOCKET_CONNECTED, WL_SOCKET_READABLE, and WL_SOCKET_WRITEABLE.

Referenced by libpqsrv_connect(), and libpqsrv_connect_params().

◆ libpqsrv_connect_params()

static PGconn * libpqsrv_connect_params ( const char *const *  keywords,
const char *const *  values,
int  expand_dbname,
uint32  wait_event_info 
)
inlinestatic

Definition at line 84 of file libpq-be-fe-helpers.h.

88{
89 PGconn *conn = NULL;
90
92
93 conn = PQconnectStartParams(keywords, values, expand_dbname);
94
95 libpqsrv_connect_internal(conn, wait_event_info);
96
97 return conn;
98}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
PGconn * PQconnectStartParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:819
static const JsonPathKeyword keywords[]

References conn, keywords, libpqsrv_connect_internal(), libpqsrv_connect_prepare(), PQconnectStartParams(), and values.

Referenced by connect_pg_server().

◆ libpqsrv_connect_prepare()

static void libpqsrv_connect_prepare ( void  )
inlinestatic

Definition at line 131 of file libpq-be-fe-helpers.h.

132{
133 /*
134 * We must obey fd.c's limit on non-virtual file descriptors. Assume that
135 * a PGconn represents one long-lived FD. (Doing this here also ensures
136 * that VFDs are closed if needed to make room.)
137 */
138 if (!AcquireExternalFD())
139 {
140#ifndef WIN32 /* can't write #if within ereport() macro */
142 (errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
143 errmsg("could not establish connection"),
144 errdetail("There are too many open files on the local server."),
145 errhint("Raise the server's \"max_files_per_process\" and/or \"ulimit -n\" limits.")));
146#else
148 (errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
149 errmsg("could not establish connection"),
150 errdetail("There are too many open files on the local server."),
151 errhint("Raise the server's \"max_files_per_process\" setting.")));
152#endif
153 }
154}
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
bool AcquireExternalFD(void)
Definition: fd.c:1185

References AcquireExternalFD(), ereport, errcode(), errdetail(), errhint(), errmsg(), and ERROR.

Referenced by libpqsrv_connect(), and libpqsrv_connect_params().

◆ libpqsrv_disconnect()

static void libpqsrv_disconnect ( PGconn conn)
inlinestatic

Definition at line 107 of file libpq-be-fe-helpers.h.

108{
109 /*
110 * If no connection was established, we haven't reserved an FD for it (or
111 * already released it). This rule makes it easier to write PG_CATCH()
112 * handlers for this facility's users.
113 *
114 * See also libpqsrv_connect_internal().
115 */
116 if (conn == NULL)
117 return;
118
120 PQfinish(conn);
121}

References conn, PQfinish(), and ReleaseExternalFD().

Referenced by connect_pg_server(), createNewConnection(), dblink_connect(), dblink_disconnect(), dblink_exec(), dblink_get_conn(), dblink_record_internal(), dblink_security_check(), and disconnect_pg_server().

◆ libpqsrv_exec()

static PGresult * libpqsrv_exec ( PGconn conn,
const char *  query,
uint32  wait_event_info 
)
inlinestatic

Definition at line 256 of file libpq-be-fe-helpers.h.

257{
258 if (!PQsendQuery(conn, query))
259 return NULL;
260 return libpqsrv_get_result_last(conn, wait_event_info);
261}
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1416
static PGresult * libpqsrv_get_result_last(PGconn *conn, uint32 wait_event_info)

References conn, libpqsrv_get_result_last(), and PQsendQuery().

Referenced by dblink_close(), dblink_exec(), dblink_fetch(), and dblink_open().

◆ libpqsrv_exec_params()

static PGresult * libpqsrv_exec_params ( PGconn conn,
const char *  command,
int  nParams,
const Oid paramTypes,
const char *const *  paramValues,
const int *  paramLengths,
const int *  paramFormats,
int  resultFormat,
uint32  wait_event_info 
)
inlinestatic

Definition at line 269 of file libpq-be-fe-helpers.h.

278{
279 if (!PQsendQueryParams(conn, command, nParams, paramTypes, paramValues,
280 paramLengths, paramFormats, resultFormat))
281 return NULL;
282 return libpqsrv_get_result_last(conn, wait_event_info);
283}
int PQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1492

References conn, libpqsrv_get_result_last(), and PQsendQueryParams().

◆ libpqsrv_get_result()

static PGresult * libpqsrv_get_result ( PGconn conn,
uint32  wait_event_info 
)
inlinestatic

Definition at line 334 of file libpq-be-fe-helpers.h.

335{
336 /*
337 * Collect data until PQgetResult is ready to get the result without
338 * blocking.
339 */
340 while (PQisBusy(conn))
341 {
342 int rc;
343
347 PQsocket(conn),
348 0,
349 wait_event_info);
350
351 /* Interrupted? */
352 if (rc & WL_LATCH_SET)
353 {
356 }
357
358 /* Consume whatever data is available from the socket */
359 if (PQconsumeInput(conn) == 0)
360 {
361 /* trouble; expect PQgetResult() to return NULL */
362 break;
363 }
364 }
365
366 /* Now we can collect and return the next PGresult */
367 return PQgetResult(conn);
368}
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:2062
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1984
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:2031

References CHECK_FOR_INTERRUPTS, conn, MyLatch, PQconsumeInput(), PQgetResult(), PQisBusy(), PQsocket(), ResetLatch(), WaitLatchOrSocket(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, and WL_SOCKET_READABLE.

Referenced by dblink_record_internal(), libpqsrv_get_result_last(), and storeQueryResult().

◆ libpqsrv_get_result_last()

static PGresult * libpqsrv_get_result_last ( PGconn conn,
uint32  wait_event_info 
)
inlinestatic

Definition at line 290 of file libpq-be-fe-helpers.h.

291{
292 PGresult *volatile lastResult = NULL;
293
294 /* In what follows, do not leak any PGresults on an error. */
295 PG_TRY();
296 {
297 for (;;)
298 {
299 /* Wait for, and collect, the next PGresult. */
300 PGresult *result;
301
302 result = libpqsrv_get_result(conn, wait_event_info);
303 if (result == NULL)
304 break; /* query is complete, or failure */
305
306 /*
307 * Emulate PQexec()'s behavior of returning the last result when
308 * there are many.
309 */
310 PQclear(lastResult);
311 lastResult = result;
312
313 if (PQresultStatus(lastResult) == PGRES_COPY_IN ||
314 PQresultStatus(lastResult) == PGRES_COPY_OUT ||
315 PQresultStatus(lastResult) == PGRES_COPY_BOTH ||
317 break;
318 }
319 }
320 PG_CATCH();
321 {
322 PQclear(lastResult);
323 PG_RE_THROW();
324 }
325 PG_END_TRY();
326
327 return lastResult;
328}
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3411
static PGresult * libpqsrv_get_result(PGconn *conn, uint32 wait_event_info)
@ PGRES_COPY_IN
Definition: libpq-fe.h:129
@ PGRES_COPY_BOTH
Definition: libpq-fe.h:134
@ PGRES_COPY_OUT
Definition: libpq-fe.h:128

References conn, CONNECTION_BAD, libpqsrv_get_result(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PGRES_COPY_BOTH, PGRES_COPY_IN, PGRES_COPY_OUT, PQclear(), PQresultStatus(), and PQstatus().

Referenced by libpqsrv_exec(), libpqsrv_exec_params(), and pgfdw_get_result().