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 char * libpqsrv_cancel (PGconn *conn, TimestampTz endtime)
 

Function Documentation

◆ libpqsrv_cancel()

static 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  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  }
446 exit: ;
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:1766
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1654
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1618
int64 TimestampTz
Definition: timestamp.h:39
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_FINALLY(...)
Definition: elog.h:387
PGcancelConn * PQcancelCreate(PGconn *conn)
Definition: fe-cancel.c:65
char * PQcancelErrorMessage(const PGcancelConn *cancelConn)
Definition: fe-cancel.c:305
PostgresPollingStatusType PQcancelPoll(PGcancelConn *cancelConn)
Definition: fe-cancel.c:207
void PQcancelFinish(PGcancelConn *cancelConn)
Definition: fe-cancel.c:333
int PQcancelSocket(const PGcancelConn *cancelConn)
Definition: fe-cancel.c:294
int PQcancelStart(PGcancelConn *cancelConn)
Definition: fe-cancel.c:185
struct Latch * MyLatch
Definition: globals.c:60
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:88
@ PGRES_POLLING_OK
Definition: libpq-fe.h:92
@ PGRES_POLLING_READING
Definition: libpq-fe.h:90
@ PGRES_POLLING_WRITING
Definition: libpq-fe.h:91
exit(1)
char * pchomp(const char *in)
Definition: mcxt.c:1711
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static void error(void)
Definition: sql-dyntest.c:147
PGconn * conn
Definition: streamutil.c:55
#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(), and pgfdw_cancel_query_begin().

◆ 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:861
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  */
176  if (PQstatus(conn) == CONNECTION_BAD)
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 
213  WL_EXIT_ON_PM_DEATH | WL_LATCH_SET | io_flag,
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:411
#define PG_CATCH(...)
Definition: elog.h:380
void ReleaseExternalFD(void)
Definition: fd.c:1239
PostgresPollingStatusType PQconnectPoll(PGconn *conn)
Definition: fe-connect.c:2547
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6895
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4669
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:6974
#define WL_SOCKET_CONNECTED
Definition: latch.h:137
@ CONNECTION_STARTED
Definition: libpq-fe.h:68
@ CONNECTION_BAD
Definition: libpq-fe.h:61
@ PGRES_POLLING_FAILED
Definition: libpq-fe.h:89

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:152
PGconn * PQconnectStartParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:780

References conn, 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 */
141  ereport(ERROR,
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
147  ereport(ERROR,
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:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
bool AcquireExternalFD(void)
Definition: fd.c:1186

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:1425
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:1501

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 }
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1960
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:2007
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:2038

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:3371
static PGresult * libpqsrv_get_result(PGconn *conn, uint32 wait_event_info)
@ PGRES_COPY_IN
Definition: libpq-fe.h:107
@ PGRES_COPY_BOTH
Definition: libpq-fe.h:112
@ PGRES_COPY_OUT
Definition: libpq-fe.h:106

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().