#include "postgres_fe.h"
#include "libpq-events.h"
#include <time.h>
#include <sys/types.h>
#include "getaddrinfo.h"
#include "libpq/pqcomm.h"
#include "pqexpbuffer.h"
Go to the source code of this file.
#define CMDSTATUS_LEN 64 |
Definition at line 88 of file libpq-int.h.
Referenced by pqParseInput2(), and pqParseInput3().
#define libpq_gettext | ( | x | ) | (x) |
Definition at line 622 of file libpq-int.h.
Referenced by connectDBStart(), connectFailureMessage(), connectNoDelay(), connectOptions2(), conninfo_add_defaults(), conninfo_array_parse(), conninfo_init(), conninfo_parse(), conninfo_storeval(), conninfo_uri_decode(), conninfo_uri_parse_options(), conninfo_uri_parse_params(), do_field(), do_header(), dot_pg_pass_warning(), getAnotherTuple(), getRowDescriptions(), handleSyncLoss(), lo_create(), lo_export(), lo_import_internal(), lo_initialize(), lo_lseek64(), lo_read(), lo_tell64(), lo_truncate(), lo_truncate64(), lo_write(), parseServiceFile(), parseServiceInfo(), PasswordFromFile(), pg_fe_sendauth(), pg_local_sendauth(), pg_password_sendauth(), PQconnectPoll(), PQdisplayTuples(), pqEndcopy2(), pqEndcopy3(), PQerrorMessage(), PQescapeByteaInternal(), PQescapeInternal(), PQescapeStringInternal(), PQexecStart(), PQfn(), pqFunctionCall2(), pqFunctionCall3(), PQgetCopyData(), pqGetCopyData2(), pqGetCopyData3(), pqGetErrorNotice3(), pqGetline3(), PQgetResult(), pqInternalNotice(), pqParseInput2(), pqParseInput3(), PQprint(), PQprintTuples(), PQputCopyData(), PQputCopyEnd(), pqReadData(), PQreset(), PQresetPoll(), PQresStatus(), pqsecure_open_client(), pqsecure_read(), pqsecure_write(), PQsendDescribe(), PQsendPrepare(), PQsendQuery(), PQsendQueryGuts(), PQsendQueryParams(), PQsendQueryPrepared(), PQsendQueryStart(), pqSendSome(), pqSetenvPoll(), pqSocketCheck(), pqWaitTimed(), reportErrorPosition(), setKeepalivesCount(), setKeepalivesIdle(), and setKeepalivesInterval().
#define NULL_LEN (-1) |
Definition at line 135 of file libpq-int.h.
Referenced by getAnotherTuple(), PQgetisnull(), PQgetlength(), and PQsetvalue().
#define pglock_thread | ( | ) | ((void) 0) |
Definition at line 512 of file libpq-int.h.
Referenced by pg_fe_getauthname(), and pg_fe_sendauth().
#define pgunlock_thread | ( | ) | ((void) 0) |
Definition at line 513 of file libpq-int.h.
Referenced by pg_fe_getauthname(), and pg_fe_sendauth().
Definition at line 615 of file libpq-int.h.
Referenced by PQconsumeInput(), pqEndcopy2(), pqEndcopy3(), PQisnonblocking(), PQputCopyData(), and pqSendSome().
#define SOCK_ERRNO errno |
Definition at line 634 of file libpq-int.h.
Referenced by connectNoDelay(), internal_cancel(), PQconnectPoll(), pqReadData(), pqSendSome(), pqSocketCheck(), setKeepalivesCount(), setKeepalivesIdle(), and setKeepalivesInterval().
Definition at line 636 of file libpq-int.h.
Referenced by internal_cancel(), pqsecure_read(), and pqsecure_write().
#define SOCK_STRERROR pqStrerror |
Definition at line 635 of file libpq-int.h.
Referenced by connectFailureMessage(), connectNoDelay(), internal_cancel(), PQconnectPoll(), pqsecure_read(), pqsecure_write(), pqSocketCheck(), setKeepalivesCount(), setKeepalivesIdle(), and setKeepalivesInterval().
typedef struct pgDataValue PGdataValue |
typedef struct pgLobjfuncs PGlobjfuncs |
typedef struct pgMessageField PGMessageField |
typedef struct pgParameterStatus pgParameterStatus |
typedef struct pgresAttValue PGresAttValue |
typedef struct pgresParamDesc PGresParamDesc |
typedef union pgresult_data PGresult_data |
Definition at line 103 of file libpq-int.h.
typedef struct PQEnvironmentOption PQEnvironmentOption |
enum PGAsyncStatusType |
PGASYNC_IDLE | |
PGASYNC_BUSY | |
PGASYNC_READY | |
PGASYNC_COPY_IN | |
PGASYNC_COPY_OUT | |
PGASYNC_COPY_BOTH |
Definition at line 215 of file libpq-int.h.
{ PGASYNC_IDLE, /* nothing's happening, dude */ PGASYNC_BUSY, /* query in progress */ PGASYNC_READY, /* result ready for PQgetResult */ PGASYNC_COPY_IN, /* Copy In data transfer in progress */ PGASYNC_COPY_OUT, /* Copy Out data transfer in progress */ PGASYNC_COPY_BOTH /* Copy In/Out data transfer in progress */ } PGAsyncStatusType;
enum PGQueryClass |
Definition at line 226 of file libpq-int.h.
{ PGQUERY_SIMPLE, /* simple Query protocol (PQexec) */ PGQUERY_EXTENDED, /* full Extended protocol (PQexecParams) */ PGQUERY_PREPARE, /* Parse only (PQprepare) */ PGQUERY_DESCRIBE /* Describe Statement or Portal */ } PGQueryClass;
enum PGSetenvStatusType |
Definition at line 236 of file libpq-int.h.
{ SETENV_STATE_CLIENT_ENCODING_SEND, /* About to send an Environment Option */ SETENV_STATE_CLIENT_ENCODING_WAIT, /* Waiting for above send to complete */ SETENV_STATE_OPTION_SEND, /* About to send an Environment Option */ SETENV_STATE_OPTION_WAIT, /* Waiting for above send to complete */ SETENV_STATE_QUERY1_SEND, /* About to send a status query */ SETENV_STATE_QUERY1_WAIT, /* Waiting for query to complete */ SETENV_STATE_QUERY2_SEND, /* About to send a status query */ SETENV_STATE_QUERY2_WAIT, /* Waiting for query to complete */ SETENV_STATE_IDLE } PGSetenvStatusType;
char* pqBuildStartupPacket2 | ( | PGconn * | conn, | |
int * | packetlen, | |||
const PQEnvironmentOption * | options | |||
) |
Definition at line 1575 of file fe-protocol2.c.
References StartupPacket::database, pg_conn::dbName, malloc, MemSet, StartupPacket::options, pg_conn::pgoptions, pg_conn::pgtty, pg_conn::pguser, StartupPacket::protoVersion, pg_conn::pversion, SM_DATABASE, SM_OPTIONS, SM_TTY, SM_USER, StartupPacket::tty, and StartupPacket::user.
Referenced by PQconnectPoll().
{ StartupPacket *startpacket; *packetlen = sizeof(StartupPacket); startpacket = (StartupPacket *) malloc(sizeof(StartupPacket)); if (!startpacket) return NULL; MemSet(startpacket, 0, sizeof(StartupPacket)); startpacket->protoVersion = htonl(conn->pversion); strncpy(startpacket->user, conn->pguser, SM_USER); strncpy(startpacket->database, conn->dbName, SM_DATABASE); strncpy(startpacket->tty, conn->pgtty, SM_TTY); if (conn->pgoptions) strncpy(startpacket->options, conn->pgoptions, SM_OPTIONS); return (char *) startpacket; }
char* pqBuildStartupPacket3 | ( | PGconn * | conn, | |
int * | packetlen, | |||
const PQEnvironmentOption * | options | |||
) |
Definition at line 1982 of file fe-protocol3.c.
References build_startup_packet(), malloc, and NULL.
Referenced by PQconnectPoll().
{ char *startpacket; *packetlen = build_startup_packet(conn, NULL, options); startpacket = (char *) malloc(*packetlen); if (!startpacket) return NULL; *packetlen = build_startup_packet(conn, startpacket, options); return startpacket; }
void pqCatenateResultError | ( | PGresult * | res, | |
const char * | msg | |||
) |
Definition at line 629 of file fe-exec.c.
References appendPQExpBufferStr(), PQExpBufferData::data, pg_result::errMsg, initPQExpBuffer(), pqSetResultError(), and termPQExpBuffer().
Referenced by PQexecFinish(), and pqSaveErrorResult().
{ PQExpBufferData errorBuf; if (!res || !msg) return; initPQExpBuffer(&errorBuf); if (res->errMsg) appendPQExpBufferStr(&errorBuf, res->errMsg); appendPQExpBufferStr(&errorBuf, msg); pqSetResultError(res, errorBuf.data); termPQExpBuffer(&errorBuf); }
int pqCheckInBufferSpace | ( | size_t | bytes_needed, | |
PGconn * | conn | |||
) |
Definition at line 412 of file fe-misc.c.
References pg_conn::errorMessage, pg_conn::inBuffer, pg_conn::inBufSize, printfPQExpBuffer(), and realloc.
Referenced by getCopyDataMessage(), PQconnectPoll(), pqFunctionCall3(), pqParseInput3(), and pqReadData().
{ int newsize = conn->inBufSize; char *newbuf; if (bytes_needed <= (size_t) newsize) return 0; /* * If we need to enlarge the buffer, we first try to double it in size; if * that doesn't work, enlarge in multiples of 8K. This avoids thrashing * the malloc pool by repeated small enlargements. * * Note: tests for newsize > 0 are to catch integer overflow. */ do { newsize *= 2; } while (newsize > 0 && bytes_needed > (size_t) newsize); if (newsize > 0 && bytes_needed <= (size_t) newsize) { newbuf = realloc(conn->inBuffer, newsize); if (newbuf) { /* realloc succeeded */ conn->inBuffer = newbuf; conn->inBufSize = newsize; return 0; } } newsize = conn->inBufSize; do { newsize += 8192; } while (newsize > 0 && bytes_needed > (size_t) newsize); if (newsize > 0 && bytes_needed <= (size_t) newsize) { newbuf = realloc(conn->inBuffer, newsize); if (newbuf) { /* realloc succeeded */ conn->inBuffer = newbuf; conn->inBufSize = newsize; return 0; } } /* realloc failed. Probably out of memory */ printfPQExpBuffer(&conn->errorMessage, "cannot allocate memory for input buffer\n"); return EOF; }
int pqCheckOutBufferSpace | ( | size_t | bytes_needed, | |
PGconn * | conn | |||
) |
Definition at line 349 of file fe-misc.c.
References pg_conn::errorMessage, pg_conn::outBuffer, pg_conn::outBufSize, printfPQExpBuffer(), and realloc.
Referenced by PQputCopyData(), pqPutMsgBytes(), and pqPutMsgStart().
{ int newsize = conn->outBufSize; char *newbuf; if (bytes_needed <= (size_t) newsize) return 0; /* * If we need to enlarge the buffer, we first try to double it in size; if * that doesn't work, enlarge in multiples of 8K. This avoids thrashing * the malloc pool by repeated small enlargements. * * Note: tests for newsize > 0 are to catch integer overflow. */ do { newsize *= 2; } while (newsize > 0 && bytes_needed > (size_t) newsize); if (newsize > 0 && bytes_needed <= (size_t) newsize) { newbuf = realloc(conn->outBuffer, newsize); if (newbuf) { /* realloc succeeded */ conn->outBuffer = newbuf; conn->outBufSize = newsize; return 0; } } newsize = conn->outBufSize; do { newsize += 8192; } while (newsize > 0 && bytes_needed > (size_t) newsize); if (newsize > 0 && bytes_needed <= (size_t) newsize) { newbuf = realloc(conn->outBuffer, newsize); if (newbuf) { /* realloc succeeded */ conn->outBuffer = newbuf; conn->outBufSize = newsize; return 0; } } /* realloc failed. Probably out of memory */ printfPQExpBuffer(&conn->errorMessage, "cannot allocate memory for output buffer\n"); return EOF; }
void pqClearAsyncResult | ( | PGconn * | conn | ) |
Definition at line 703 of file fe-exec.c.
References pg_conn::next_result, PQclear(), and pg_conn::result.
Referenced by closePGconn(), getAnotherTuple(), getRowDescriptions(), pqGetErrorNotice2(), pqGetErrorNotice3(), and pqSaveErrorResult().
{ if (conn->result) PQclear(conn->result); conn->result = NULL; if (conn->next_result) PQclear(conn->next_result); conn->next_result = NULL; }
void pqDropConnection | ( | PGconn * | conn | ) |
Definition at line 396 of file fe-connect.c.
References closesocket, pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, pg_conn::outCount, pqsecure_close(), and pg_conn::sock.
Referenced by closePGconn(), connectDBStart(), handleSyncLoss(), PQconnectPoll(), and pqReadData().
{ /* Drop any SSL state */ pqsecure_close(conn); /* Close the socket itself */ if (conn->sock >= 0) closesocket(conn->sock); conn->sock = -1; /* Discard any unread/unsent data */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; }
int pqEndcopy2 | ( | PGconn * | conn | ) |
Definition at line 1319 of file fe-protocol2.c.
References pg_conn::asyncStatus, PQExpBufferData::data, pg_conn::errorMessage, PQExpBufferData::len, libpq_gettext, pg_conn::noticeHooks, PGASYNC_COPY_IN, PGASYNC_COPY_OUT, PGRES_COMMAND_OK, PQclear(), pqFlush(), PQgetResult(), pqInternalNotice(), PQisBusy(), pqIsnonblocking, PQreset(), PQresetStart(), printfPQExpBuffer(), resetPQExpBuffer(), and pg_result::resultStatus.
Referenced by PQendcopy().
{ PGresult *result; if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_OUT) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return 1; } /* * make sure no data is waiting to be sent, abort if we are non-blocking * and the flush fails */ if (pqFlush(conn) && pqIsnonblocking(conn)) return 1; /* non blocking connections may have to abort at this point. */ if (pqIsnonblocking(conn) && PQisBusy(conn)) return 1; /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; resetPQExpBuffer(&conn->errorMessage); /* Wait for the completion response */ result = PQgetResult(conn); /* Expecting a successful result */ if (result && result->resultStatus == PGRES_COMMAND_OK) { PQclear(result); return 0; } /* * Trouble. For backwards-compatibility reasons, we issue the error * message as if it were a notice (would be nice to get rid of this * silliness, but too many apps probably don't handle errors from * PQendcopy reasonably). Note that the app can still obtain the error * status from the PGconn object. */ if (conn->errorMessage.len > 0) { /* We have to strip the trailing newline ... pain in neck... */ char svLast = conn->errorMessage.data[conn->errorMessage.len - 1]; if (svLast == '\n') conn->errorMessage.data[conn->errorMessage.len - 1] = '\0'; pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data); conn->errorMessage.data[conn->errorMessage.len - 1] = svLast; } PQclear(result); /* * The worst case is that we've lost sync with the backend entirely due to * application screwup of the copy in/out protocol. To recover, reset the * connection (talk about using a sledgehammer...) */ pqInternalNotice(&conn->noticeHooks, "lost synchronization with server, resetting connection"); /* * Users doing non-blocking connections need to handle the reset * themselves, they'll need to check the connection status if we return an * error. */ if (pqIsnonblocking(conn)) PQresetStart(conn); else PQreset(conn); return 1; }
int pqEndcopy3 | ( | PGconn * | conn | ) |
Definition at line 1672 of file fe-protocol3.c.
References pg_conn::asyncStatus, PQExpBufferData::data, pg_conn::errorMessage, PQExpBufferData::len, libpq_gettext, pg_conn::noticeHooks, PGASYNC_COPY_BOTH, PGASYNC_COPY_IN, PGASYNC_COPY_OUT, PGQUERY_SIMPLE, PGRES_COMMAND_OK, PQclear(), pqFlush(), PQgetResult(), pqInternalNotice(), PQisBusy(), pqIsnonblocking, pqPutMsgEnd(), pqPutMsgStart(), printfPQExpBuffer(), pg_conn::queryclass, resetPQExpBuffer(), and pg_result::resultStatus.
Referenced by PQendcopy().
{ PGresult *result; if (conn->asyncStatus != PGASYNC_COPY_IN && conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_BOTH) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("no COPY in progress\n")); return 1; } /* Send the CopyDone message if needed */ if (conn->asyncStatus == PGASYNC_COPY_IN || conn->asyncStatus == PGASYNC_COPY_BOTH) { if (pqPutMsgStart('c', false, conn) < 0 || pqPutMsgEnd(conn) < 0) return 1; /* * If we sent the COPY command in extended-query mode, we must issue a * Sync as well. */ if (conn->queryclass != PGQUERY_SIMPLE) { if (pqPutMsgStart('S', false, conn) < 0 || pqPutMsgEnd(conn) < 0) return 1; } } /* * make sure no data is waiting to be sent, abort if we are non-blocking * and the flush fails */ if (pqFlush(conn) && pqIsnonblocking(conn)) return 1; /* Return to active duty */ conn->asyncStatus = PGASYNC_BUSY; resetPQExpBuffer(&conn->errorMessage); /* * Non blocking connections may have to abort at this point. If everyone * played the game there should be no problem, but in error scenarios the * expected messages may not have arrived yet. (We are assuming that the * backend's packetizing will ensure that CommandComplete arrives along * with the CopyDone; are there corner cases where that doesn't happen?) */ if (pqIsnonblocking(conn) && PQisBusy(conn)) return 1; /* Wait for the completion response */ result = PQgetResult(conn); /* Expecting a successful result */ if (result && result->resultStatus == PGRES_COMMAND_OK) { PQclear(result); return 0; } /* * Trouble. For backwards-compatibility reasons, we issue the error * message as if it were a notice (would be nice to get rid of this * silliness, but too many apps probably don't handle errors from * PQendcopy reasonably). Note that the app can still obtain the error * status from the PGconn object. */ if (conn->errorMessage.len > 0) { /* We have to strip the trailing newline ... pain in neck... */ char svLast = conn->errorMessage.data[conn->errorMessage.len - 1]; if (svLast == '\n') conn->errorMessage.data[conn->errorMessage.len - 1] = '\0'; pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data); conn->errorMessage.data[conn->errorMessage.len - 1] = svLast; } PQclear(result); return 1; }
int pqFlush | ( | PGconn * | conn | ) |
Definition at line 920 of file fe-misc.c.
References pg_conn::outCount, pg_conn::Pfdebug, and pqSendSome().
Referenced by closePGconn(), PQconnectPoll(), PQconsumeInput(), pqEndcopy2(), pqEndcopy3(), PQflush(), pqFunctionCall2(), pqFunctionCall3(), PQgetResult(), pqPacketSend(), PQputCopyData(), PQputCopyEnd(), PQsendDescribe(), PQsendPrepare(), PQsendQuery(), PQsendQueryGuts(), and PQsetnonblocking().
{ if (conn->Pfdebug) fflush(conn->Pfdebug); if (conn->outCount > 0) return pqSendSome(conn, conn->outCount); return 0; }
PGresult* pqFunctionCall2 | ( | PGconn * | conn, | |
Oid | fnid, | |||
int * | result_buf, | |||
int * | actual_result_len, | |||
int | result_is_int, | |||
const PQArgBlock * | args, | |||
int | nargs | |||
) |
Definition at line 1404 of file fe-protocol2.c.
References pg_conn::errorMessage, FALSE, getNotify(), i, pg_conn::inCursor, pg_conn::inStart, PQArgBlock::integer, PQArgBlock::len, libpq_gettext, pqFlush(), pqGetc(), pqGetErrorNotice2(), pqGetInt(), pqGetnchar(), pqHandleSendFailure(), PQmakeEmptyPGresult(), pqPrepareAsyncResult(), pqPutInt(), pqPutMsgEnd(), pqPutMsgStart(), pqPutnchar(), pqPuts(), pqReadData(), pqSaveErrorResult(), pqWait(), printfPQExpBuffer(), PQArgBlock::ptr, pg_conn::result, status(), and TRUE.
Referenced by PQfn().
{ bool needInput = false; ExecStatusType status = PGRES_FATAL_ERROR; char id; int i; /* PQfn already validated connection state */ if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */ pqPuts(" ", conn) < 0 || /* dummy string */ pqPutInt(fnid, 4, conn) != 0 || /* function id */ pqPutInt(nargs, 4, conn) != 0) /* # of args */ { pqHandleSendFailure(conn); return NULL; } for (i = 0; i < nargs; ++i) { /* len.int4 + contents */ if (pqPutInt(args[i].len, 4, conn)) { pqHandleSendFailure(conn); return NULL; } if (args[i].isint) { if (pqPutInt(args[i].u.integer, 4, conn)) { pqHandleSendFailure(conn); return NULL; } } else { if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn)) { pqHandleSendFailure(conn); return NULL; } } } if (pqPutMsgEnd(conn) < 0 || pqFlush(conn)) { pqHandleSendFailure(conn); return NULL; } for (;;) { if (needInput) { /* Wait for some data to arrive (or for the channel to close) */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) break; } /* * Scan the message. If we run out of data, loop around to try again. */ conn->inCursor = conn->inStart; needInput = true; if (pqGetc(&id, conn)) continue; /* * We should see V or E response to the command, but might get N * and/or A notices first. We also need to swallow the final Z before * returning. */ switch (id) { case 'V': /* function result */ if (pqGetc(&id, conn)) continue; if (id == 'G') { /* function returned nonempty value */ if (pqGetInt(actual_result_len, 4, conn)) continue; if (result_is_int) { if (pqGetInt(result_buf, 4, conn)) continue; } else { if (pqGetnchar((char *) result_buf, *actual_result_len, conn)) continue; } if (pqGetc(&id, conn)) /* get the last '0' */ continue; } if (id == '0') { /* correctly finished function result message */ status = PGRES_COMMAND_OK; } else { /* The backend violates the protocol. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); conn->inStart = conn->inCursor; return pqPrepareAsyncResult(conn); } break; case 'E': /* error return */ if (pqGetErrorNotice2(conn, true)) continue; status = PGRES_FATAL_ERROR; break; case 'A': /* notify message */ /* handle notify and go back to processing return values */ if (getNotify(conn)) continue; break; case 'N': /* notice */ /* handle notice and go back to processing return values */ if (pqGetErrorNotice2(conn, false)) continue; break; case 'Z': /* backend is ready for new query */ /* consume the message and exit */ conn->inStart = conn->inCursor; /* if we saved a result object (probably an error), use it */ if (conn->result) return pqPrepareAsyncResult(conn); return PQmakeEmptyPGresult(conn, status); default: /* The backend violates the protocol. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); conn->inStart = conn->inCursor; return pqPrepareAsyncResult(conn); } /* Completed this message, keep going */ conn->inStart = conn->inCursor; needInput = false; } /* * We fall out of the loop only upon failing to read data. * conn->errorMessage has been set by pqWait or pqReadData. We want to * append it to any already-received error message. */ pqSaveErrorResult(conn); return pqPrepareAsyncResult(conn); }
PGresult* pqFunctionCall3 | ( | PGconn * | conn, | |
Oid | fnid, | |||
int * | result_buf, | |||
int * | actual_result_len, | |||
int | result_is_int, | |||
const PQArgBlock * | args, | |||
int | nargs | |||
) |
Definition at line 1766 of file fe-protocol3.c.
References pg_conn::errorMessage, FALSE, getNotify(), getParameterStatus(), getReadyForQuery(), handleSyncLoss(), i, pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, PQArgBlock::integer, PQArgBlock::len, libpq_gettext, pqCheckInBufferSpace(), pqFlush(), pqGetc(), pqGetErrorNotice3(), pqGetInt(), pqGetnchar(), pqHandleSendFailure(), PQmakeEmptyPGresult(), pqPrepareAsyncResult(), pqPutInt(), pqPutMsgEnd(), pqPutMsgStart(), pqPutnchar(), pqReadData(), pqSaveErrorResult(), pqWait(), printfPQExpBuffer(), PQArgBlock::ptr, pg_conn::result, status(), TRUE, and VALID_LONG_MESSAGE_TYPE.
Referenced by PQfn().
{ bool needInput = false; ExecStatusType status = PGRES_FATAL_ERROR; char id; int msgLength; int avail; int i; /* PQfn already validated connection state */ if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */ pqPutInt(fnid, 4, conn) < 0 || /* function id */ pqPutInt(1, 2, conn) < 0 || /* # of format codes */ pqPutInt(1, 2, conn) < 0 || /* format code: BINARY */ pqPutInt(nargs, 2, conn) < 0) /* # of args */ { pqHandleSendFailure(conn); return NULL; } for (i = 0; i < nargs; ++i) { /* len.int4 + contents */ if (pqPutInt(args[i].len, 4, conn)) { pqHandleSendFailure(conn); return NULL; } if (args[i].len == -1) continue; /* it's NULL */ if (args[i].isint) { if (pqPutInt(args[i].u.integer, args[i].len, conn)) { pqHandleSendFailure(conn); return NULL; } } else { if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn)) { pqHandleSendFailure(conn); return NULL; } } } if (pqPutInt(1, 2, conn) < 0) /* result format code: BINARY */ { pqHandleSendFailure(conn); return NULL; } if (pqPutMsgEnd(conn) < 0 || pqFlush(conn)) { pqHandleSendFailure(conn); return NULL; } for (;;) { if (needInput) { /* Wait for some data to arrive (or for the channel to close) */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) break; } /* * Scan the message. If we run out of data, loop around to try again. */ needInput = true; conn->inCursor = conn->inStart; if (pqGetc(&id, conn)) continue; if (pqGetInt(&msgLength, 4, conn)) continue; /* * Try to validate message type/length here. A length less than 4 is * definitely broken. Large lengths should only be believed for a few * message types. */ if (msgLength < 4) { handleSyncLoss(conn, id, msgLength); break; } if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id)) { handleSyncLoss(conn, id, msgLength); break; } /* * Can't process if message body isn't all here yet. */ msgLength -= 4; avail = conn->inEnd - conn->inCursor; if (avail < msgLength) { /* * Before looping, enlarge the input buffer if needed to hold the * whole message. See notes in parseInput. */ if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength, conn)) { /* * XXX add some better recovery code... plan is to skip over * the message using its length, then report an error. For the * moment, just treat this like loss of sync (which indeed it * might be!) */ handleSyncLoss(conn, id, msgLength); break; } continue; } /* * We should see V or E response to the command, but might get N * and/or A notices first. We also need to swallow the final Z before * returning. */ switch (id) { case 'V': /* function result */ if (pqGetInt(actual_result_len, 4, conn)) continue; if (*actual_result_len != -1) { if (result_is_int) { if (pqGetInt(result_buf, *actual_result_len, conn)) continue; } else { if (pqGetnchar((char *) result_buf, *actual_result_len, conn)) continue; } } /* correctly finished function result message */ status = PGRES_COMMAND_OK; break; case 'E': /* error return */ if (pqGetErrorNotice3(conn, true)) continue; status = PGRES_FATAL_ERROR; break; case 'A': /* notify message */ /* handle notify and go back to processing return values */ if (getNotify(conn)) continue; break; case 'N': /* notice */ /* handle notice and go back to processing return values */ if (pqGetErrorNotice3(conn, false)) continue; break; case 'Z': /* backend is ready for new query */ if (getReadyForQuery(conn)) continue; /* consume the message and exit */ conn->inStart += 5 + msgLength; /* if we saved a result object (probably an error), use it */ if (conn->result) return pqPrepareAsyncResult(conn); return PQmakeEmptyPGresult(conn, status); case 'S': /* parameter status */ if (getParameterStatus(conn)) continue; break; default: /* The backend violates the protocol. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("protocol error: id=0x%x\n"), id); pqSaveErrorResult(conn); /* trust the specified message length as what to skip */ conn->inStart += 5 + msgLength; return pqPrepareAsyncResult(conn); } /* Completed this message, keep going */ /* trust the specified message length as what to skip */ conn->inStart += 5 + msgLength; needInput = false; } /* * We fall out of the loop only upon failing to read data. * conn->errorMessage has been set by pqWait or pqReadData. We want to * append it to any already-received error message. */ pqSaveErrorResult(conn); return pqPrepareAsyncResult(conn); }
int pqGetc | ( | char * | result, | |
PGconn * | conn | |||
) |
Definition at line 99 of file fe-misc.c.
References pg_conn::inBuffer, pg_conn::inCursor, pg_conn::inEnd, and pg_conn::Pfdebug.
Referenced by getCopyDataMessage(), getCopyStart(), getReadyForQuery(), PQconnectPoll(), pqFunctionCall2(), pqFunctionCall3(), pqGetErrorNotice3(), pqParseInput2(), and pqParseInput3().
int pqGetCopyData2 | ( | PGconn * | conn, | |
char ** | buffer, | |||
int | async | |||
) |
Definition at line 1136 of file fe-protocol2.c.
References pg_conn::asyncStatus, pg_conn::errorMessage, FALSE, pg_conn::inBuffer, pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, libpq_gettext, malloc, NULL, pqReadData(), pqWait(), printfPQExpBuffer(), and TRUE.
Referenced by PQgetCopyData().
{ bool found; int msgLength; for (;;) { /* * Do we have a complete line of data? */ conn->inCursor = conn->inStart; found = false; while (conn->inCursor < conn->inEnd) { char c = conn->inBuffer[conn->inCursor++]; if (c == '\n') { found = true; break; } } if (!found) goto nodata; msgLength = conn->inCursor - conn->inStart; /* * If it's the end-of-data marker, consume it, exit COPY_OUT mode, and * let caller read status with PQgetResult(). */ if (msgLength == 3 && strncmp(&conn->inBuffer[conn->inStart], "\\.\n", 3) == 0) { conn->inStart = conn->inCursor; conn->asyncStatus = PGASYNC_BUSY; return -1; } /* * Pass the line back to the caller. */ *buffer = (char *) malloc(msgLength + 1); if (*buffer == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return -2; } memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength); (*buffer)[msgLength] = '\0'; /* Add terminating null */ /* Mark message consumed */ conn->inStart = conn->inCursor; return msgLength; nodata: /* Don't block if async read requested */ if (async) return 0; /* Need to load more data */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) return -2; } }
int pqGetCopyData3 | ( | PGconn * | conn, | |
char ** | buffer, | |||
int | async | |||
) |
Definition at line 1505 of file fe-protocol3.c.
References pg_conn::errorMessage, FALSE, getCopyDataMessage(), pg_conn::inBuffer, pg_conn::inCursor, pg_conn::inStart, libpq_gettext, malloc, NULL, pqReadData(), pqWait(), printfPQExpBuffer(), and TRUE.
Referenced by PQgetCopyData().
{ int msgLength; for (;;) { /* * Collect the next input message. To make life simpler for async * callers, we keep returning 0 until the next message is fully * available, even if it is not Copy Data. */ msgLength = getCopyDataMessage(conn); if (msgLength < 0) return msgLength; /* end-of-copy or error */ if (msgLength == 0) { /* Don't block if async read requested */ if (async) return 0; /* Need to load more data */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) return -2; continue; } /* * Drop zero-length messages (shouldn't happen anyway). Otherwise * pass the data back to the caller. */ msgLength -= 4; if (msgLength > 0) { *buffer = (char *) malloc(msgLength + 1); if (*buffer == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return -2; } memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength); (*buffer)[msgLength] = '\0'; /* Add terminating null */ /* Mark message consumed */ conn->inStart = conn->inCursor + msgLength; return msgLength; } /* Empty, so drop it and loop around for another */ conn->inStart = conn->inCursor; } }
Definition at line 804 of file fe-protocol3.c.
References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), pg_conn::client_encoding, PQExpBufferData::data, pg_result::errMsg, pg_conn::errorMessage, initPQExpBuffer(), pg_conn::last_query, pg_conn::last_sqlstate, libpq_gettext, pg_result::noticeHooks, PGNoticeHooks::noticeRec, PGNoticeHooks::noticeRecArg, NULL, PG_DIAG_COLUMN_NAME, PG_DIAG_CONSTRAINT_NAME, PG_DIAG_CONTEXT, PG_DIAG_DATATYPE_NAME, PG_DIAG_INTERNAL_POSITION, PG_DIAG_INTERNAL_QUERY, PG_DIAG_MESSAGE_DETAIL, PG_DIAG_MESSAGE_HINT, PG_DIAG_MESSAGE_PRIMARY, PG_DIAG_SCHEMA_NAME, PG_DIAG_SEVERITY, PG_DIAG_SOURCE_FILE, PG_DIAG_SOURCE_FUNCTION, PG_DIAG_SOURCE_LINE, PG_DIAG_SQLSTATE, PG_DIAG_STATEMENT_POSITION, PG_DIAG_TABLE_NAME, PGRES_EMPTY_QUERY, PGRES_FATAL_ERROR, PQclear(), pqClearAsyncResult(), PQERRORS_TERSE, PQERRORS_VERBOSE, pqGetc(), pqGets(), PQmakeEmptyPGresult(), PQresultErrorField(), pqResultStrdup(), pqSaveMessageField(), reportErrorPosition(), resetPQExpBuffer(), pg_conn::result, pg_result::resultStatus, termPQExpBuffer(), val, and pg_conn::verbosity.
Referenced by getCopyDataMessage(), PQconnectPoll(), pqFunctionCall3(), and pqParseInput3().
{ PGresult *res = NULL; PQExpBufferData workBuf; char id; const char *val; const char *querytext = NULL; int querypos = 0; /* * Since the fields might be pretty long, we create a temporary * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended * for stuff that is expected to be short. We shouldn't use * conn->errorMessage either, since this might be only a notice. */ initPQExpBuffer(&workBuf); /* * Make a PGresult to hold the accumulated fields. We temporarily lie * about the result status, so that PQmakeEmptyPGresult doesn't uselessly * copy conn->errorMessage. */ res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); if (!res) goto fail; res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; /* * Read the fields and save into res. */ for (;;) { if (pqGetc(&id, conn)) goto fail; if (id == '\0') break; /* terminator found */ if (pqGets(&workBuf, conn)) goto fail; pqSaveMessageField(res, id, workBuf.data); } /* * Now build the "overall" error message for PQresultErrorMessage. * * Also, save the SQLSTATE in conn->last_sqlstate. */ resetPQExpBuffer(&workBuf); val = PQresultErrorField(res, PG_DIAG_SEVERITY); if (val) appendPQExpBuffer(&workBuf, "%s: ", val); val = PQresultErrorField(res, PG_DIAG_SQLSTATE); if (val) { if (strlen(val) < sizeof(conn->last_sqlstate)) strcpy(conn->last_sqlstate, val); if (conn->verbosity == PQERRORS_VERBOSE) appendPQExpBuffer(&workBuf, "%s: ", val); } val = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); if (val) appendPQExpBufferStr(&workBuf, val); val = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION); if (val) { if (conn->verbosity != PQERRORS_TERSE && conn->last_query != NULL) { /* emit position as a syntax cursor display */ querytext = conn->last_query; querypos = atoi(val); } else { /* emit position as text addition to primary message */ /* translator: %s represents a digit string */ appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"), val); } } else { val = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION); if (val) { querytext = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY); if (conn->verbosity != PQERRORS_TERSE && querytext != NULL) { /* emit position as a syntax cursor display */ querypos = atoi(val); } else { /* emit position as text addition to primary message */ /* translator: %s represents a digit string */ appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"), val); } } } appendPQExpBufferChar(&workBuf, '\n'); if (conn->verbosity != PQERRORS_TERSE) { if (querytext && querypos > 0) reportErrorPosition(&workBuf, querytext, querypos, conn->client_encoding); val = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("HINT: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("QUERY: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_CONTEXT); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT: %s\n"), val); } if (conn->verbosity == PQERRORS_VERBOSE) { val = PQresultErrorField(res, PG_DIAG_SCHEMA_NAME); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("SCHEMA NAME: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_TABLE_NAME); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("TABLE NAME: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("COLUMN NAME: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_DATATYPE_NAME); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("DATATYPE NAME: %s\n"), val); val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_NAME); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("CONSTRAINT NAME: %s\n"), val); } if (conn->verbosity == PQERRORS_VERBOSE) { const char *valf; const char *vall; valf = PQresultErrorField(res, PG_DIAG_SOURCE_FILE); vall = PQresultErrorField(res, PG_DIAG_SOURCE_LINE); val = PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION); if (val || valf || vall) { appendPQExpBufferStr(&workBuf, libpq_gettext("LOCATION: ")); if (val) appendPQExpBuffer(&workBuf, libpq_gettext("%s, "), val); if (valf && vall) /* unlikely we'd have just one */ appendPQExpBuffer(&workBuf, libpq_gettext("%s:%s"), valf, vall); appendPQExpBufferChar(&workBuf, '\n'); } } /* * Either save error as current async result, or just emit the notice. */ if (isError) { res->errMsg = pqResultStrdup(res, workBuf.data); if (!res->errMsg) goto fail; pqClearAsyncResult(conn); conn->result = res; appendPQExpBufferStr(&conn->errorMessage, workBuf.data); } else { /* We can cheat a little here and not copy the message. */ res->errMsg = workBuf.data; if (res->noticeHooks.noticeRec != NULL) (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); PQclear(res); } termPQExpBuffer(&workBuf); return 0; fail: PQclear(res); termPQExpBuffer(&workBuf); return EOF; }
bool pqGetHomeDirectory | ( | char * | buf, | |
int | bufsize | |||
) |
Definition at line 5672 of file fe-connect.c.
References NULL, pqGetpwuid(), snprintf(), and strlcpy().
Referenced by getPgPassFilename(), and parseServiceInfo().
{ #ifndef WIN32 char pwdbuf[BUFSIZ]; struct passwd pwdstr; struct passwd *pwd = NULL; if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0) return false; strlcpy(buf, pwd->pw_dir, bufsize); return true; #else char tmppath[MAX_PATH]; ZeroMemory(tmppath, sizeof(tmppath)); if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, tmppath) != S_OK) return false; snprintf(buf, bufsize, "%s/postgresql", tmppath); return true; #endif }
int pqGetInt | ( | int * | result, | |
size_t | bytes, | |||
PGconn * | conn | |||
) |
Definition at line 272 of file fe-misc.c.
References pg_conn::inBuffer, pg_conn::inCursor, pg_conn::inEnd, pg_conn::noticeHooks, pg_conn::Pfdebug, and pqInternalNotice().
Referenced by getAnotherTuple(), getCopyDataMessage(), getCopyStart(), getNotify(), getParamDescriptions(), getRowDescriptions(), PQconnectPoll(), pqFunctionCall2(), pqFunctionCall3(), pqParseInput2(), and pqParseInput3().
{ uint16 tmp2; uint32 tmp4; switch (bytes) { case 2: if (conn->inCursor + 2 > conn->inEnd) return EOF; memcpy(&tmp2, conn->inBuffer + conn->inCursor, 2); conn->inCursor += 2; *result = (int) ntohs(tmp2); break; case 4: if (conn->inCursor + 4 > conn->inEnd) return EOF; memcpy(&tmp4, conn->inBuffer + conn->inCursor, 4); conn->inCursor += 4; *result = (int) ntohl(tmp4); break; default: pqInternalNotice(&conn->noticeHooks, "integer of size %lu not supported by pqGetInt", (unsigned long) bytes); return EOF; } if (conn->Pfdebug) fprintf(conn->Pfdebug, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result); return 0; }
int pqGetline2 | ( | PGconn * | conn, | |
char * | s, | |||
int | maxlen | |||
) |
Definition at line 1210 of file fe-protocol2.c.
References pg_conn::asyncStatus, FALSE, pg_conn::inBuffer, pg_conn::inEnd, pg_conn::inStart, PGASYNC_COPY_OUT, pqReadData(), pqWait(), pg_conn::sock, and TRUE.
Referenced by PQgetline().
{ int result = 1; /* return value if buffer overflows */ if (conn->sock < 0 || conn->asyncStatus != PGASYNC_COPY_OUT) { *s = '\0'; return EOF; } /* * Since this is a purely synchronous routine, we don't bother to maintain * conn->inCursor; there is no need to back up. */ while (maxlen > 1) { if (conn->inStart < conn->inEnd) { char c = conn->inBuffer[conn->inStart++]; if (c == '\n') { result = 0; /* success exit */ break; } *s++ = c; maxlen--; } else { /* need to load more data */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) { result = EOF; break; } } } *s = '\0'; return result; }
int pqGetline3 | ( | PGconn * | conn, | |
char * | s, | |||
int | maxlen | |||
) |
Definition at line 1565 of file fe-protocol3.c.
References pg_conn::asyncStatus, pg_conn::copy_is_binary, pg_conn::errorMessage, FALSE, libpq_gettext, PGASYNC_COPY_BOTH, PGASYNC_COPY_OUT, PQgetlineAsync(), pqReadData(), pqWait(), printfPQExpBuffer(), pg_conn::sock, and TRUE.
Referenced by PQgetline().
{ int status; if (conn->sock < 0 || (conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_BOTH) || conn->copy_is_binary) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("PQgetline: not doing text COPY OUT\n")); *s = '\0'; return EOF; } while ((status = PQgetlineAsync(conn, s, maxlen - 1)) == 0) { /* need to load more data */ if (pqWait(TRUE, FALSE, conn) || pqReadData(conn) < 0) { *s = '\0'; return EOF; } } if (status < 0) { /* End of copy detected; gin up old-style terminator */ strcpy(s, "\\."); return 0; } /* Add null terminator, and strip trailing \n if present */ if (s[status - 1] == '\n') { s[status - 1] = '\0'; return 0; } else { s[status] = '\0'; return 1; } }
int pqGetlineAsync2 | ( | PGconn * | conn, | |
char * | buffer, | |||
int | bufsize | |||
) |
Definition at line 1261 of file fe-protocol2.c.
References pg_conn::asyncStatus, pg_conn::inBuffer, pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, and PGASYNC_COPY_OUT.
Referenced by PQgetlineAsync().
{ int avail; if (conn->asyncStatus != PGASYNC_COPY_OUT) return -1; /* we are not doing a copy... */ /* * Move data from libpq's buffer to the caller's. We want to accept data * only in units of whole lines, not partial lines. This ensures that we * can recognize the terminator line "\\.\n". (Otherwise, if it happened * to cross a packet/buffer boundary, we might hand the first one or two * characters off to the caller, which we shouldn't.) */ conn->inCursor = conn->inStart; avail = bufsize; while (avail > 0 && conn->inCursor < conn->inEnd) { char c = conn->inBuffer[conn->inCursor++]; *buffer++ = c; --avail; if (c == '\n') { /* Got a complete line; mark the data removed from libpq */ conn->inStart = conn->inCursor; /* Is it the endmarker line? */ if (bufsize - avail == 3 && buffer[-3] == '\\' && buffer[-2] == '.') return -1; /* No, return the data line to the caller */ return bufsize - avail; } } /* * We don't have a complete line. We'd prefer to leave it in libpq's * buffer until the rest arrives, but there is a special case: what if the * line is longer than the buffer the caller is offering us? In that case * we'd better hand over a partial line, else we'd get into an infinite * loop. Do this in a way that ensures we can't misrecognize a terminator * line later: leave last 3 characters in libpq buffer. */ if (avail == 0 && bufsize > 3) { conn->inStart = conn->inCursor - 3; return bufsize - 3; } return 0; }
int pqGetlineAsync3 | ( | PGconn * | conn, | |
char * | buffer, | |||
int | bufsize | |||
) |
Definition at line 1617 of file fe-protocol3.c.
References pg_conn::asyncStatus, pg_conn::copy_already_done, getCopyDataMessage(), pg_conn::inBuffer, pg_conn::inCursor, pg_conn::inStart, PGASYNC_COPY_BOTH, and PGASYNC_COPY_OUT.
Referenced by PQgetlineAsync().
{ int msgLength; int avail; if (conn->asyncStatus != PGASYNC_COPY_OUT && conn->asyncStatus != PGASYNC_COPY_BOTH) return -1; /* we are not doing a copy... */ /* * Recognize the next input message. To make life simpler for async * callers, we keep returning 0 until the next message is fully available * even if it is not Copy Data. This should keep PQendcopy from blocking. * (Note: unlike pqGetCopyData3, we do not change asyncStatus here.) */ msgLength = getCopyDataMessage(conn); if (msgLength < 0) return -1; /* end-of-copy or error */ if (msgLength == 0) return 0; /* no data yet */ /* * Move data from libpq's buffer to the caller's. In the case where a * prior call found the caller's buffer too small, we use * conn->copy_already_done to remember how much of the row was already * returned to the caller. */ conn->inCursor += conn->copy_already_done; avail = msgLength - 4 - conn->copy_already_done; if (avail <= bufsize) { /* Able to consume the whole message */ memcpy(buffer, &conn->inBuffer[conn->inCursor], avail); /* Mark message consumed */ conn->inStart = conn->inCursor + avail; /* Reset state for next time */ conn->copy_already_done = 0; return avail; } else { /* We must return a partial message */ memcpy(buffer, &conn->inBuffer[conn->inCursor], bufsize); /* The message is NOT consumed from libpq's buffer */ conn->copy_already_done += bufsize; return bufsize; } }
int pqGetnchar | ( | char * | s, | |
size_t | len, | |||
PGconn * | conn | |||
) |
Definition at line 200 of file fe-misc.c.
References fputnbytes(), pg_conn::inBuffer, pg_conn::inCursor, pg_conn::inEnd, and pg_conn::Pfdebug.
Referenced by getAnotherTuple(), PQconnectPoll(), pqFunctionCall2(), and pqFunctionCall3().
{ if (len > (size_t) (conn->inEnd - conn->inCursor)) return EOF; memcpy(s, conn->inBuffer + conn->inCursor, len); /* no terminating null */ conn->inCursor += len; if (conn->Pfdebug) { fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len); fputnbytes(conn->Pfdebug, s, len); fprintf(conn->Pfdebug, "\n"); } return 0; }
int pqGets | ( | PQExpBuffer | buf, | |
PGconn * | conn | |||
) |
Definition at line 168 of file fe-misc.c.
References pqGets_internal().
Referenced by getNotify(), getParameterStatus(), getRowDescriptions(), pqGetErrorNotice2(), pqGetErrorNotice3(), pqParseInput2(), and pqParseInput3().
{ return pqGets_internal(buf, conn, true); }
int pqGets_append | ( | PQExpBuffer | buf, | |
PGconn * | conn | |||
) |
Definition at line 174 of file fe-misc.c.
References pqGets_internal().
Referenced by PQconnectPoll().
{ return pqGets_internal(buf, conn, false); }
void pqHandleSendFailure | ( | PGconn * | conn | ) |
Definition at line 1560 of file fe-exec.c.
References parseInput(), and pqReadData().
Referenced by pqFunctionCall2(), pqFunctionCall3(), PQsendDescribe(), PQsendPrepare(), PQsendQuery(), and PQsendQueryGuts().
{ /* * Accept any available input data, ignoring errors. Note that if * pqReadData decides the backend has closed the channel, it will close * our side of the socket --- that's just what we want here. */ while (pqReadData(conn) > 0) /* loop until no more data readable */ ; /* * Parse any available input messages. Since we are in PGASYNC_IDLE * state, only NOTICE and NOTIFY messages will be eaten. */ parseInput(conn); }
void pqInternalNotice | ( | const PGNoticeHooks * | hooks, | |
const char * | fmt, | |||
... | ||||
) |
int pqPacketSend | ( | PGconn * | conn, | |
char | pack_type, | |||
const void * | buf, | |||
size_t | buf_len | |||
) |
Definition at line 3307 of file fe-connect.c.
References pqFlush(), pqPutMsgEnd(), pqPutMsgStart(), and pqPutnchar().
Referenced by pg_password_sendauth(), and PQconnectPoll().
{ /* Start the message. */ if (pqPutMsgStart(pack_type, true, conn)) return STATUS_ERROR; /* Send the message body. */ if (pqPutnchar(buf, buf_len, conn)) return STATUS_ERROR; /* Finish the message. */ if (pqPutMsgEnd(conn)) return STATUS_ERROR; /* Flush to ensure backend gets it. */ if (pqFlush(conn)) return STATUS_ERROR; return STATUS_OK; }
void pqParseInput2 | ( | PGconn * | conn | ) |
Definition at line 411 of file fe-protocol2.c.
References pg_conn::asyncStatus, pg_conn::be_key, pg_conn::be_pid, checkXactStatus(), pg_result::cmdStatus, CMDSTATUS_LEN, PQExpBufferData::data, pg_conn::errorMessage, FALSE, getAnotherTuple(), getNotify(), getRowDescriptions(), pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, libpq_gettext, pg_conn::noticeHooks, NULL, PGASYNC_BUSY, PGASYNC_COPY_OUT, PGASYNC_IDLE, PGRES_COMMAND_OK, PGRES_EMPTY_QUERY, pqGetc(), pqGetErrorNotice2(), pqGetInt(), pqGets(), pqInternalNotice(), PQmakeEmptyPGresult(), pqSaveErrorResult(), printfPQExpBuffer(), pg_conn::result, TRUE, and pg_conn::workBuffer.
Referenced by parseInput().
{ char id; /* * Loop to parse successive complete messages available in the buffer. */ for (;;) { /* * Quit if in COPY_OUT state: we expect raw data from the server until * PQendcopy is called. Don't try to parse it according to the normal * protocol. (This is bogus. The data lines ought to be part of the * protocol and have identifying leading characters.) */ if (conn->asyncStatus == PGASYNC_COPY_OUT) return; /* * OK to try to read a message type code. */ conn->inCursor = conn->inStart; if (pqGetc(&id, conn)) return; /* * NOTIFY and NOTICE messages can happen in any state besides COPY * OUT; always process them right away. * * Most other messages should only be processed while in BUSY state. * (In particular, in READY state we hold off further parsing until * the application collects the current PGresult.) * * However, if the state is IDLE then we got trouble; we need to deal * with the unexpected message somehow. */ if (id == 'A') { if (getNotify(conn)) return; } else if (id == 'N') { if (pqGetErrorNotice2(conn, false)) return; } else if (conn->asyncStatus != PGASYNC_BUSY) { /* If not IDLE state, just wait ... */ if (conn->asyncStatus != PGASYNC_IDLE) return; /* * Unexpected message in IDLE state; need to recover somehow. * ERROR messages are displayed using the notice processor; * anything else is just dropped on the floor after displaying a * suitable warning notice. (An ERROR is very possibly the * backend telling us why it is about to close the connection, so * we don't want to just discard it...) */ if (id == 'E') { if (pqGetErrorNotice2(conn, false /* treat as notice */ )) return; } else { pqInternalNotice(&conn->noticeHooks, "message type 0x%02x arrived from server while idle", id); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; break; } } else { /* * In BUSY state, we can process everything. */ switch (id) { case 'C': /* command complete */ if (pqGets(&conn->workBuffer, conn)) return; if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) return; } strncpy(conn->result->cmdStatus, conn->workBuffer.data, CMDSTATUS_LEN); checkXactStatus(conn, conn->workBuffer.data); conn->asyncStatus = PGASYNC_READY; break; case 'E': /* error return */ if (pqGetErrorNotice2(conn, true)) return; conn->asyncStatus = PGASYNC_READY; break; case 'Z': /* backend is ready for new query */ conn->asyncStatus = PGASYNC_IDLE; break; case 'I': /* empty query */ /* read and throw away the closing '\0' */ if (pqGetc(&id, conn)) return; if (id != '\0') pqInternalNotice(&conn->noticeHooks, "unexpected character %c following empty query response (\"I\" message)", id); if (conn->result == NULL) conn->result = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); conn->asyncStatus = PGASYNC_READY; break; case 'K': /* secret key data from the backend */ /* * This is expected only during backend startup, but it's * just as easy to handle it as part of the main loop. * Save the data and continue processing. */ if (pqGetInt(&(conn->be_pid), 4, conn)) return; if (pqGetInt(&(conn->be_key), 4, conn)) return; break; case 'P': /* synchronous (normal) portal */ if (pqGets(&conn->workBuffer, conn)) return; /* We pretty much ignore this message type... */ break; case 'T': /* row descriptions (start of query results) */ if (conn->result == NULL) { /* First 'T' in a query sequence */ if (getRowDescriptions(conn)) return; /* getRowDescriptions() moves inStart itself */ continue; } else { /* * A new 'T' message is treated as the start of * another PGresult. (It is not clear that this is * really possible with the current backend.) We stop * parsing until the application accepts the current * result. */ conn->asyncStatus = PGASYNC_READY; return; } break; case 'D': /* ASCII data tuple */ if (conn->result != NULL) { /* Read another tuple of a normal query response */ if (getAnotherTuple(conn, FALSE)) return; /* getAnotherTuple() moves inStart itself */ continue; } else { pqInternalNotice(&conn->noticeHooks, "server sent data (\"D\" message) without prior row description (\"T\" message)"); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; return; } break; case 'B': /* Binary data tuple */ if (conn->result != NULL) { /* Read another tuple of a normal query response */ if (getAnotherTuple(conn, TRUE)) return; /* getAnotherTuple() moves inStart itself */ continue; } else { pqInternalNotice(&conn->noticeHooks, "server sent binary data (\"B\" message) without prior row description (\"T\" message)"); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; return; } break; case 'G': /* Start Copy In */ conn->asyncStatus = PGASYNC_COPY_IN; break; case 'H': /* Start Copy Out */ conn->asyncStatus = PGASYNC_COPY_OUT; break; /* * Don't need to process CopyBothResponse here because it * never arrives from the server during protocol 2.0. */ default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "unexpected response from server; first received character was \"%c\"\n"), id); /* build an error result holding the error message */ pqSaveErrorResult(conn); /* Discard the unexpected message; good idea?? */ conn->inStart = conn->inEnd; conn->asyncStatus = PGASYNC_READY; return; } /* switch on protocol character */ } /* Successfully consumed this message */ conn->inStart = conn->inCursor; } }
void pqParseInput3 | ( | PGconn * | conn | ) |
Definition at line 66 of file fe-protocol3.c.
References pg_conn::asyncStatus, pg_conn::be_key, pg_conn::be_pid, pg_result::cmdStatus, CMDSTATUS_LEN, pg_conn::copy_already_done, PQExpBufferData::data, pg_conn::errorMessage, getAnotherTuple(), getCopyStart(), getNotify(), getParamDescriptions(), getParameterStatus(), getReadyForQuery(), getRowDescriptions(), handleSyncLoss(), pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, libpq_gettext, pg_conn::noticeHooks, NULL, PGASYNC_BUSY, PGASYNC_IDLE, PGQUERY_DESCRIBE, PGQUERY_PREPARE, PGRES_COMMAND_OK, PGRES_COPY_BOTH, PGRES_COPY_IN, PGRES_COPY_OUT, PGRES_EMPTY_QUERY, PGRES_FATAL_ERROR, PGRES_TUPLES_OK, pqCheckInBufferSpace(), pqGetc(), pqGetErrorNotice3(), pqGetInt(), pqGets(), pqInternalNotice(), PQmakeEmptyPGresult(), pqSaveErrorResult(), printfPQExpBuffer(), pg_conn::queryclass, pg_conn::result, pg_result::resultStatus, VALID_LONG_MESSAGE_TYPE, and pg_conn::workBuffer.
Referenced by parseInput().
{ char id; int msgLength; int avail; /* * Loop to parse successive complete messages available in the buffer. */ for (;;) { /* * Try to read a message. First get the type code and length. Return * if not enough data. */ conn->inCursor = conn->inStart; if (pqGetc(&id, conn)) return; if (pqGetInt(&msgLength, 4, conn)) return; /* * Try to validate message type/length here. A length less than 4 is * definitely broken. Large lengths should only be believed for a few * message types. */ if (msgLength < 4) { handleSyncLoss(conn, id, msgLength); return; } if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id)) { handleSyncLoss(conn, id, msgLength); return; } /* * Can't process if message body isn't all here yet. */ msgLength -= 4; avail = conn->inEnd - conn->inCursor; if (avail < msgLength) { /* * Before returning, enlarge the input buffer if needed to hold * the whole message. This is better than leaving it to * pqReadData because we can avoid multiple cycles of realloc() * when the message is large; also, we can implement a reasonable * recovery strategy if we are unable to make the buffer big * enough. */ if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength, conn)) { /* * XXX add some better recovery code... plan is to skip over * the message using its length, then report an error. For the * moment, just treat this like loss of sync (which indeed it * might be!) */ handleSyncLoss(conn, id, msgLength); } return; } /* * NOTIFY and NOTICE messages can happen in any state; always process * them right away. * * Most other messages should only be processed while in BUSY state. * (In particular, in READY state we hold off further parsing until * the application collects the current PGresult.) * * However, if the state is IDLE then we got trouble; we need to deal * with the unexpected message somehow. * * ParameterStatus ('S') messages are a special case: in IDLE state we * must process 'em (this case could happen if a new value was adopted * from config file due to SIGHUP), but otherwise we hold off until * BUSY state. */ if (id == 'A') { if (getNotify(conn)) return; } else if (id == 'N') { if (pqGetErrorNotice3(conn, false)) return; } else if (conn->asyncStatus != PGASYNC_BUSY) { /* If not IDLE state, just wait ... */ if (conn->asyncStatus != PGASYNC_IDLE) return; /* * Unexpected message in IDLE state; need to recover somehow. * ERROR messages are displayed using the notice processor; * ParameterStatus is handled normally; anything else is just * dropped on the floor after displaying a suitable warning * notice. (An ERROR is very possibly the backend telling us why * it is about to close the connection, so we don't want to just * discard it...) */ if (id == 'E') { if (pqGetErrorNotice3(conn, false /* treat as notice */ )) return; } else if (id == 'S') { if (getParameterStatus(conn)) return; } else { pqInternalNotice(&conn->noticeHooks, "message type 0x%02x arrived from server while idle", id); /* Discard the unexpected message */ conn->inCursor += msgLength; } } else { /* * In BUSY state, we can process everything. */ switch (id) { case 'C': /* command complete */ if (pqGets(&conn->workBuffer, conn)) return; if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) return; } strncpy(conn->result->cmdStatus, conn->workBuffer.data, CMDSTATUS_LEN); conn->asyncStatus = PGASYNC_READY; break; case 'E': /* error return */ if (pqGetErrorNotice3(conn, true)) return; conn->asyncStatus = PGASYNC_READY; break; case 'Z': /* backend is ready for new query */ if (getReadyForQuery(conn)) return; conn->asyncStatus = PGASYNC_IDLE; break; case 'I': /* empty query */ if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); if (!conn->result) return; } conn->asyncStatus = PGASYNC_READY; break; case '1': /* Parse Complete */ /* If we're doing PQprepare, we're done; else ignore */ if (conn->queryclass == PGQUERY_PREPARE) { if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) return; } conn->asyncStatus = PGASYNC_READY; } break; case '2': /* Bind Complete */ case '3': /* Close Complete */ /* Nothing to do for these message types */ break; case 'S': /* parameter status */ if (getParameterStatus(conn)) return; break; case 'K': /* secret key data from the backend */ /* * This is expected only during backend startup, but it's * just as easy to handle it as part of the main loop. * Save the data and continue processing. */ if (pqGetInt(&(conn->be_pid), 4, conn)) return; if (pqGetInt(&(conn->be_key), 4, conn)) return; break; case 'T': /* Row Description */ if (conn->result == NULL || conn->queryclass == PGQUERY_DESCRIBE) { /* First 'T' in a query sequence */ if (getRowDescriptions(conn, msgLength)) return; /* getRowDescriptions() moves inStart itself */ continue; } else { /* * A new 'T' message is treated as the start of * another PGresult. (It is not clear that this is * really possible with the current backend.) We stop * parsing until the application accepts the current * result. */ conn->asyncStatus = PGASYNC_READY; return; } break; case 'n': /* No Data */ /* * NoData indicates that we will not be seeing a * RowDescription message because the statement or portal * inquired about doesn't return rows. * * If we're doing a Describe, we have to pass something * back to the client, so set up a COMMAND_OK result, * instead of TUPLES_OK. Otherwise we can just ignore * this message. */ if (conn->queryclass == PGQUERY_DESCRIBE) { if (conn->result == NULL) { conn->result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); if (!conn->result) return; } conn->asyncStatus = PGASYNC_READY; } break; case 't': /* Parameter Description */ if (getParamDescriptions(conn)) return; break; case 'D': /* Data Row */ if (conn->result != NULL && conn->result->resultStatus == PGRES_TUPLES_OK) { /* Read another tuple of a normal query response */ if (getAnotherTuple(conn, msgLength)) return; /* getAnotherTuple() moves inStart itself */ continue; } else if (conn->result != NULL && conn->result->resultStatus == PGRES_FATAL_ERROR) { /* * We've already choked for some reason. Just discard * tuples till we get to the end of the query. */ conn->inCursor += msgLength; } else { /* Set up to report error at end of query */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n")); pqSaveErrorResult(conn); /* Discard the unexpected message */ conn->inCursor += msgLength; } break; case 'G': /* Start Copy In */ if (getCopyStart(conn, PGRES_COPY_IN)) return; conn->asyncStatus = PGASYNC_COPY_IN; break; case 'H': /* Start Copy Out */ if (getCopyStart(conn, PGRES_COPY_OUT)) return; conn->asyncStatus = PGASYNC_COPY_OUT; conn->copy_already_done = 0; break; case 'W': /* Start Copy Both */ if (getCopyStart(conn, PGRES_COPY_BOTH)) return; conn->asyncStatus = PGASYNC_COPY_BOTH; conn->copy_already_done = 0; break; case 'd': /* Copy Data */ /* * If we see Copy Data, just silently drop it. This would * only occur if application exits COPY OUT mode too * early. */ conn->inCursor += msgLength; break; case 'c': /* Copy Done */ /* * If we see Copy Done, just silently drop it. This is * the normal case during PQendcopy. We will keep * swallowing data, expecting to see command-complete for * the COPY command. */ break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "unexpected response from server; first received character was \"%c\"\n"), id); /* build an error result holding the error message */ pqSaveErrorResult(conn); /* not sure if we will see more, so go to ready state */ conn->asyncStatus = PGASYNC_READY; /* Discard the unexpected message */ conn->inCursor += msgLength; break; } /* switch on protocol character */ } /* Successfully consumed this message */ if (conn->inCursor == conn->inStart + 5 + msgLength) { /* Normal case: parsing agrees with specified length */ conn->inStart = conn->inCursor; } else { /* Trouble --- report it */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("message contents do not agree with length in message type \"%c\"\n"), id); /* build an error result holding the error message */ pqSaveErrorResult(conn); conn->asyncStatus = PGASYNC_READY; /* trust the specified message length as what to skip */ conn->inStart += 5 + msgLength; } } }
Definition at line 754 of file fe-exec.c.
References appendPQExpBufferStr(), pg_conn::errorMessage, pg_conn::next_result, PGRES_FATAL_ERROR, PQmakeEmptyPGresult(), PQresultErrorMessage(), resetPQExpBuffer(), and pg_conn::result.
Referenced by pqFunctionCall2(), pqFunctionCall3(), and PQgetResult().
{ PGresult *res; /* * conn->result is the PGresult to return. If it is NULL (which probably * shouldn't happen) we assume there is an appropriate error message in * conn->errorMessage. */ res = conn->result; if (!res) res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); else { /* * Make sure PQerrorMessage agrees with result; it could be different * if we have concatenated messages. */ resetPQExpBuffer(&conn->errorMessage); appendPQExpBufferStr(&conn->errorMessage, PQresultErrorMessage(res)); } /* * Replace conn->result with next_result, if any. In the normal case * there isn't a next result and we're just dropping ownership of the * current result. In single-row mode this restores the situation to what * it was before we created the current single-row result. */ conn->result = conn->next_result; conn->next_result = NULL; return res; }
int pqPutc | ( | char | c, | |
PGconn * | conn | |||
) |
Definition at line 117 of file fe-misc.c.
References pg_conn::Pfdebug, and pqPutMsgBytes().
Referenced by PQsendDescribe(), and PQsendQueryGuts().
{ if (pqPutMsgBytes(&c, 1, conn)) return EOF; if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend> %c\n", c); return 0; }
int pqPutInt | ( | int | value, | |
size_t | bytes, | |||
PGconn * | conn | |||
) |
Definition at line 312 of file fe-misc.c.
References pg_conn::noticeHooks, pg_conn::Pfdebug, pqInternalNotice(), and pqPutMsgBytes().
Referenced by pqFunctionCall2(), pqFunctionCall3(), PQsendPrepare(), and PQsendQueryGuts().
{ uint16 tmp2; uint32 tmp4; switch (bytes) { case 2: tmp2 = htons((uint16) value); if (pqPutMsgBytes((const char *) &tmp2, 2, conn)) return EOF; break; case 4: tmp4 = htonl((uint32) value); if (pqPutMsgBytes((const char *) &tmp4, 4, conn)) return EOF; break; default: pqInternalNotice(&conn->noticeHooks, "integer of size %lu not supported by pqPutInt", (unsigned long) bytes); return EOF; } if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend (%lu#)> %d\n", (unsigned long) bytes, value); return 0; }
int pqPutMsgEnd | ( | PGconn * | conn | ) |
Definition at line 560 of file fe-misc.c.
References pg_conn::outBuffer, pg_conn::outCount, pg_conn::outMsgEnd, pg_conn::outMsgStart, pg_conn::Pfdebug, and pqSendSome().
Referenced by closePGconn(), pqEndcopy3(), pqFunctionCall2(), pqFunctionCall3(), pqPacketSend(), PQputCopyData(), PQputCopyEnd(), PQsendDescribe(), PQsendPrepare(), PQsendQuery(), and PQsendQueryGuts().
{ if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n", conn->outMsgEnd - conn->outCount); /* Fill in length word if needed */ if (conn->outMsgStart >= 0) { uint32 msgLen = conn->outMsgEnd - conn->outMsgStart; msgLen = htonl(msgLen); memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4); } /* Make message eligible to send */ conn->outCount = conn->outMsgEnd; if (conn->outCount >= 8192) { int toSend = conn->outCount - (conn->outCount % 8192); if (pqSendSome(conn, toSend) < 0) return EOF; /* in nonblock mode, don't complain if unable to send it all */ } return 0; }
Definition at line 492 of file fe-misc.c.
References pg_conn::outBuffer, pg_conn::outCount, pg_conn::outMsgEnd, pg_conn::outMsgStart, pg_conn::Pfdebug, PG_PROTOCOL_MAJOR, pqCheckOutBufferSpace(), and pg_conn::pversion.
Referenced by closePGconn(), pqEndcopy3(), pqFunctionCall2(), pqFunctionCall3(), pqPacketSend(), PQputCopyData(), PQputCopyEnd(), PQsendDescribe(), PQsendPrepare(), PQsendQuery(), and PQsendQueryGuts().
{ int lenPos; int endPos; /* allow room for message type byte */ if (msg_type) endPos = conn->outCount + 1; else endPos = conn->outCount; /* do we want a length word? */ if (force_len || PG_PROTOCOL_MAJOR(conn->pversion) >= 3) { lenPos = endPos; /* allow room for message length */ endPos += 4; } else lenPos = -1; /* make sure there is room for message header */ if (pqCheckOutBufferSpace(endPos, conn)) return EOF; /* okay, save the message type byte if any */ if (msg_type) conn->outBuffer[conn->outCount] = msg_type; /* set up the message pointers */ conn->outMsgStart = lenPos; conn->outMsgEnd = endPos; /* length word, if needed, will be filled in by pqPutMsgEnd */ if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend> Msg %c\n", msg_type ? msg_type : ' '); return 0; }
int pqPutnchar | ( | const char * | s, | |
size_t | len, | |||
PGconn * | conn | |||
) |
Definition at line 251 of file fe-misc.c.
References fputnbytes(), pg_conn::Pfdebug, and pqPutMsgBytes().
Referenced by pqFunctionCall2(), pqFunctionCall3(), pqPacketSend(), PQputCopyData(), PQputCopyEnd(), and PQsendQueryGuts().
{ if (pqPutMsgBytes(s, len, conn)) return EOF; if (conn->Pfdebug) { fprintf(conn->Pfdebug, "To backend> "); fputnbytes(conn->Pfdebug, s, len); fprintf(conn->Pfdebug, "\n"); } return 0; }
int pqPuts | ( | const char * | s, | |
PGconn * | conn | |||
) |
Definition at line 184 of file fe-misc.c.
References pg_conn::Pfdebug, and pqPutMsgBytes().
Referenced by pqFunctionCall2(), PQputCopyEnd(), PQsendDescribe(), PQsendPrepare(), PQsendQuery(), and PQsendQueryGuts().
{ if (pqPutMsgBytes(s, strlen(s) + 1, conn)) return EOF; if (conn->Pfdebug) fprintf(conn->Pfdebug, "To backend> \"%s\"\n", s); return 0; }
int pqReadData | ( | PGconn * | conn | ) |
Definition at line 602 of file fe-misc.c.
References EAGAIN, ECONNRESET, EINTR, pg_conn::errorMessage, EWOULDBLOCK, pg_conn::inBuffer, pg_conn::inBufSize, pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, libpq_gettext, memmove, pqCheckInBufferSpace(), pqDropConnection(), pqReadReady(), pqsecure_read(), printfPQExpBuffer(), pg_conn::sock, SOCK_ERRNO, and pg_conn::status.
Referenced by PQconnectPoll(), PQconsumeInput(), pqFunctionCall2(), pqFunctionCall3(), pqGetCopyData2(), pqGetCopyData3(), pqGetline2(), pqGetline3(), PQgetResult(), pqHandleSendFailure(), pqSendSome(), and pqSetenvPoll().
{ int someread = 0; int nread; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("connection not open\n")); return -1; } /* Left-justify any data in the buffer to make room */ if (conn->inStart < conn->inEnd) { if (conn->inStart > 0) { memmove(conn->inBuffer, conn->inBuffer + conn->inStart, conn->inEnd - conn->inStart); conn->inEnd -= conn->inStart; conn->inCursor -= conn->inStart; conn->inStart = 0; } } else { /* buffer is logically empty, reset it */ conn->inStart = conn->inCursor = conn->inEnd = 0; } /* * If the buffer is fairly full, enlarge it. We need to be able to enlarge * the buffer in case a single message exceeds the initial buffer size. We * enlarge before filling the buffer entirely so as to avoid asking the * kernel for a partial packet. The magic constant here should be large * enough for a TCP packet or Unix pipe bufferload. 8K is the usual pipe * buffer size, so... */ if (conn->inBufSize - conn->inEnd < 8192) { if (pqCheckInBufferSpace(conn->inEnd + (size_t) 8192, conn)) { /* * We don't insist that the enlarge worked, but we need some room */ if (conn->inBufSize - conn->inEnd < 100) return -1; /* errorMessage already set */ } } /* OK, try to read some data */ retry3: nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd); if (nread < 0) { if (SOCK_ERRNO == EINTR) goto retry3; /* Some systems return EAGAIN/EWOULDBLOCK for no data */ #ifdef EAGAIN if (SOCK_ERRNO == EAGAIN) return someread; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) if (SOCK_ERRNO == EWOULDBLOCK) return someread; #endif /* We might get ECONNRESET here if using TCP and backend died */ #ifdef ECONNRESET if (SOCK_ERRNO == ECONNRESET) goto definitelyFailed; #endif /* pqsecure_read set the error message for us */ return -1; } if (nread > 0) { conn->inEnd += nread; /* * Hack to deal with the fact that some kernels will only give us back * 1 packet per recv() call, even if we asked for more and there is * more available. If it looks like we are reading a long message, * loop back to recv() again immediately, until we run out of data or * buffer space. Without this, the block-and-restart behavior of * libpq's higher levels leads to O(N^2) performance on long messages. * * Since we left-justified the data above, conn->inEnd gives the * amount of data already read in the current message. We consider * the message "long" once we have acquired 32k ... */ if (conn->inEnd > 32768 && (conn->inBufSize - conn->inEnd) >= 8192) { someread = 1; goto retry3; } return 1; } if (someread) return 1; /* got a zero read after successful tries */ /* * A return value of 0 could mean just that no data is now available, or * it could mean EOF --- that is, the server has closed the connection. * Since we have the socket in nonblock mode, the only way to tell the * difference is to see if select() is saying that the file is ready. * Grumble. Fortunately, we don't expect this path to be taken much, * since in normal practice we should not be trying to read data unless * the file selected for reading already. * * In SSL mode it's even worse: SSL_read() could say WANT_READ and then * data could arrive before we make the pqReadReady() test. So we must * play dumb and assume there is more data, relying on the SSL layer to * detect true EOF. */ #ifdef USE_SSL if (conn->ssl) return 0; #endif switch (pqReadReady(conn)) { case 0: /* definitely no data available */ return 0; case 1: /* ready for read */ break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); goto definitelyFailed; } /* * Still not sure that it's EOF, because some data could have just * arrived. */ retry4: nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd); if (nread < 0) { if (SOCK_ERRNO == EINTR) goto retry4; /* Some systems return EAGAIN/EWOULDBLOCK for no data */ #ifdef EAGAIN if (SOCK_ERRNO == EAGAIN) return 0; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) if (SOCK_ERRNO == EWOULDBLOCK) return 0; #endif /* We might get ECONNRESET here if using TCP and backend died */ #ifdef ECONNRESET if (SOCK_ERRNO == ECONNRESET) goto definitelyFailed; #endif /* pqsecure_read set the error message for us */ return -1; } if (nread > 0) { conn->inEnd += nread; return 1; } /* * OK, we are getting a zero read even though select() says ready. This * means the connection has been closed. Cope. Note that errorMessage * has been set already. */ definitelyFailed: pqDropConnection(conn); conn->status = CONNECTION_BAD; /* No more connection to backend */ return -1; }
int pqReadReady | ( | PGconn * | conn | ) |
Definition at line 982 of file fe-misc.c.
References pqSocketCheck().
Referenced by pqReadData().
{ return pqSocketCheck(conn, 1, 0, (time_t) 0); }
Definition at line 504 of file fe-exec.c.
References pg_result::curBlock, pg_result::curOffset, malloc, pgresult_data::next, pg_result::null_field, PGRESULT_ALIGN_BOUNDARY, PGRESULT_BLOCK_OVERHEAD, PGRESULT_DATA_BLOCKSIZE, PGRESULT_SEP_ALLOC_THRESHOLD, pgresult_data::space, and pg_result::spaceLeft.
Referenced by getCopyStart(), getParamDescriptions(), getRowDescriptions(), pqInternalNotice(), PQresultAlloc(), pqResultStrdup(), pqRowProcessor(), pqSaveMessageField(), and PQsetvalue().
{ char *space; PGresult_data *block; if (!res) return NULL; if (nBytes <= 0) return res->null_field; /* * If alignment is needed, round up the current position to an alignment * boundary. */ if (isBinary) { int offset = res->curOffset % PGRESULT_ALIGN_BOUNDARY; if (offset) { res->curOffset += PGRESULT_ALIGN_BOUNDARY - offset; res->spaceLeft -= PGRESULT_ALIGN_BOUNDARY - offset; } } /* If there's enough space in the current block, no problem. */ if (nBytes <= (size_t) res->spaceLeft) { space = res->curBlock->space + res->curOffset; res->curOffset += nBytes; res->spaceLeft -= nBytes; return space; } /* * If the requested object is very large, give it its own block; this * avoids wasting what might be most of the current block to start a new * block. (We'd have to special-case requests bigger than the block size * anyway.) The object is always given binary alignment in this case. */ if (nBytes >= PGRESULT_SEP_ALLOC_THRESHOLD) { block = (PGresult_data *) malloc(nBytes + PGRESULT_BLOCK_OVERHEAD); if (!block) return NULL; space = block->space + PGRESULT_BLOCK_OVERHEAD; if (res->curBlock) { /* * Tuck special block below the active block, so that we don't * have to waste the free space in the active block. */ block->next = res->curBlock->next; res->curBlock->next = block; } else { /* Must set up the new block as the first active block. */ block->next = NULL; res->curBlock = block; res->spaceLeft = 0; /* be sure it's marked full */ } return space; } /* Otherwise, start a new block. */ block = (PGresult_data *) malloc(PGRESULT_DATA_BLOCKSIZE); if (!block) return NULL; block->next = res->curBlock; res->curBlock = block; if (isBinary) { /* object needs full alignment */ res->curOffset = PGRESULT_BLOCK_OVERHEAD; res->spaceLeft = PGRESULT_DATA_BLOCKSIZE - PGRESULT_BLOCK_OVERHEAD; } else { /* we can cram it right after the overhead pointer */ res->curOffset = sizeof(PGresult_data); res->spaceLeft = PGRESULT_DATA_BLOCKSIZE - sizeof(PGresult_data); } space = block->space + res->curOffset; res->curOffset += nBytes; res->spaceLeft -= nBytes; return space; }
char* pqResultStrdup | ( | PGresult * | res, | |
const char * | str | |||
) |
Definition at line 600 of file fe-exec.c.
References pqResultAlloc().
Referenced by getRowDescriptions(), pqGetErrorNotice2(), pqGetErrorNotice3(), PQsetResultAttrs(), and pqSetResultError().
{ char *space = (char *) pqResultAlloc(res, strlen(str) + 1, FALSE); if (space) strcpy(space, str); return space; }
int pqRowProcessor | ( | PGconn * | conn, | |
const char ** | errmsgp | |||
) |
Definition at line 1009 of file fe-exec.c.
References pg_conn::asyncStatus, pg_result::attDescs, pgresAttDesc::format, i, pgresAttValue::len, pgDataValue::len, pg_conn::next_result, NULL, pg_result::null_field, pg_result::numAttributes, PG_COPYRES_ATTRS, PG_COPYRES_EVENTS, PG_COPYRES_NOTICEHOOKS, pqAddTuple(), PQclear(), PQcopyResult(), pqResultAlloc(), pg_conn::result, pg_result::resultStatus, pg_conn::rowBuf, pg_conn::singleRowMode, val, value, and pgresAttValue::value.
Referenced by getAnotherTuple().
{ PGresult *res = conn->result; int nfields = res->numAttributes; const PGdataValue *columns = conn->rowBuf; PGresAttValue *tup; int i; /* * In single-row mode, make a new PGresult that will hold just this one * row; the original conn->result is left unchanged so that it can be used * again as the template for future rows. */ if (conn->singleRowMode) { /* Copy everything that should be in the result at this point */ res = PQcopyResult(res, PG_COPYRES_ATTRS | PG_COPYRES_EVENTS | PG_COPYRES_NOTICEHOOKS); if (!res) return 0; } /* * Basically we just allocate space in the PGresult for each field and * copy the data over. * * Note: on malloc failure, we return 0 leaving *errmsgp still NULL, which * caller will take to mean "out of memory". This is preferable to trying * to set up such a message here, because evidently there's not enough * memory for gettext() to do anything. */ tup = (PGresAttValue *) pqResultAlloc(res, nfields * sizeof(PGresAttValue), TRUE); if (tup == NULL) goto fail; for (i = 0; i < nfields; i++) { int clen = columns[i].len; if (clen < 0) { /* null field */ tup[i].len = NULL_LEN; tup[i].value = res->null_field; } else { bool isbinary = (res->attDescs[i].format != 0); char *val; val = (char *) pqResultAlloc(res, clen + 1, isbinary); if (val == NULL) goto fail; /* copy and zero-terminate the data (even if it's binary) */ memcpy(val, columns[i].value, clen); val[clen] = '\0'; tup[i].len = clen; tup[i].value = val; } } /* And add the tuple to the PGresult's tuple array */ if (!pqAddTuple(res, tup)) goto fail; /* * Success. In single-row mode, make the result available to the client * immediately. */ if (conn->singleRowMode) { /* Change result status to special single-row value */ res->resultStatus = PGRES_SINGLE_TUPLE; /* Stash old result for re-use later */ conn->next_result = conn->result; conn->result = res; /* And mark the result ready to return */ conn->asyncStatus = PGASYNC_READY; } return 1; fail: /* release locally allocated PGresult, if we made one */ if (res != conn->result) PQclear(res); return 0; }
void pqSaveErrorResult | ( | PGconn * | conn | ) |
Definition at line 726 of file fe-exec.c.
References PQExpBufferData::data, pg_result::errMsg, pg_conn::errorMessage, NULL, PGRES_FATAL_ERROR, pqCatenateResultError(), pqClearAsyncResult(), PQmakeEmptyPGresult(), pg_conn::result, and pg_result::resultStatus.
Referenced by getAnotherTuple(), getRowDescriptions(), handleSyncLoss(), pqFunctionCall2(), pqFunctionCall3(), PQgetResult(), pqParseInput2(), and pqParseInput3().
{ /* * If no old async result, just let PQmakeEmptyPGresult make one. Likewise * if old result is not an error message. */ if (conn->result == NULL || conn->result->resultStatus != PGRES_FATAL_ERROR || conn->result->errMsg == NULL) { pqClearAsyncResult(conn); conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); } else { /* Else, concatenate error message to existing async result. */ pqCatenateResultError(conn->result, conn->errorMessage.data); } }
void void pqSaveMessageField | ( | PGresult * | res, | |
char | code, | |||
const char * | value | |||
) |
Definition at line 888 of file fe-exec.c.
References pgMessageField::code, pgMessageField::contents, pg_result::errFields, pgMessageField::next, and pqResultAlloc().
Referenced by pqGetErrorNotice2(), pqGetErrorNotice3(), and pqInternalNotice().
{ PGMessageField *pfield; pfield = (PGMessageField *) pqResultAlloc(res, sizeof(PGMessageField) + strlen(value), TRUE); if (!pfield) return; /* out of memory? */ pfield->code = code; strcpy(pfield->contents, value); pfield->next = res->errFields; res->errFields = pfield; }
void pqSaveParameterStatus | ( | PGconn * | conn, | |
const char * | name, | |||
const char * | value | |||
) |
Definition at line 908 of file fe-exec.c.
References pg_conn::client_encoding, free, malloc, pgParameterStatus::name, pgParameterStatus::next, NULL, pg_conn::Pfdebug, pg_char_to_encoding(), pg_conn::pstatus, static_client_encoding, static_std_strings, pg_conn::std_strings, pg_conn::sversion, and pgParameterStatus::value.
Referenced by getParameterStatus(), PQsetClientEncoding(), and pqSetenvPoll().
{ pgParameterStatus *pstatus; pgParameterStatus *prev; if (conn->Pfdebug) fprintf(conn->Pfdebug, "pqSaveParameterStatus: '%s' = '%s'\n", name, value); /* * Forget any old information about the parameter */ for (pstatus = conn->pstatus, prev = NULL; pstatus != NULL; prev = pstatus, pstatus = pstatus->next) { if (strcmp(pstatus->name, name) == 0) { if (prev) prev->next = pstatus->next; else conn->pstatus = pstatus->next; free(pstatus); /* frees name and value strings too */ break; } } /* * Store new info as a single malloc block */ pstatus = (pgParameterStatus *) malloc(sizeof(pgParameterStatus) + strlen(name) +strlen(value) + 2); if (pstatus) { char *ptr; ptr = ((char *) pstatus) + sizeof(pgParameterStatus); pstatus->name = ptr; strcpy(ptr, name); ptr += strlen(name) + 1; pstatus->value = ptr; strcpy(ptr, value); pstatus->next = conn->pstatus; conn->pstatus = pstatus; } /* * Special hacks: remember client_encoding and * standard_conforming_strings, and convert server version to a numeric * form. We keep the first two of these in static variables as well, so * that PQescapeString and PQescapeBytea can behave somewhat sanely (at * least in single-connection-using programs). */ if (strcmp(name, "client_encoding") == 0) { conn->client_encoding = pg_char_to_encoding(value); /* if we don't recognize the encoding name, fall back to SQL_ASCII */ if (conn->client_encoding < 0) conn->client_encoding = PG_SQL_ASCII; static_client_encoding = conn->client_encoding; } else if (strcmp(name, "standard_conforming_strings") == 0) { conn->std_strings = (strcmp(value, "on") == 0); static_std_strings = conn->std_strings; } else if (strcmp(name, "server_version") == 0) { int cnt; int vmaj, vmin, vrev; cnt = sscanf(value, "%d.%d.%d", &vmaj, &vmin, &vrev); if (cnt < 2) conn->sversion = 0; /* unknown */ else { if (cnt == 2) vrev = 0; conn->sversion = (100 * vmaj + vmin) * 100 + vrev; } } }
void pqsecure_close | ( | PGconn * | ) |
Definition at line 294 of file fe-secure.c.
Referenced by pqDropConnection().
void pqsecure_destroy | ( | void | ) |
Definition at line 236 of file fe-secure.c.
{ #ifdef USE_SSL destroySSL(); #endif }
int pqsecure_initialize | ( | PGconn * | ) |
Definition at line 221 of file fe-secure.c.
Referenced by PQconnectPoll().
{ int r = 0; #ifdef USE_SSL r = init_ssl_system(conn); #endif return r; }
PostgresPollingStatusType pqsecure_open_client | ( | PGconn * | ) |
Definition at line 247 of file fe-secure.c.
References pg_conn::errorMessage, libpq_gettext, NULL, printfPQExpBuffer(), pg_conn::sigpipe_flag, and pg_conn::sock.
Referenced by PQconnectPoll().
{ #ifdef USE_SSL /* First time through? */ if (conn->ssl == NULL) { /* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */ conn->sigpipe_flag = false; /* Create a connection-specific SSL object */ if (!(conn->ssl = SSL_new(SSL_context)) || !SSL_set_app_data(conn->ssl, conn) || !SSL_set_fd(conn->ssl, conn->sock)) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not establish SSL connection: %s\n"), err); SSLerrfree(err); close_SSL(conn); return PGRES_POLLING_FAILED; } /* * Load client certificate, private key, and trusted CA certs. */ if (initialize_SSL(conn) != 0) { /* initialize_SSL already put a message in conn->errorMessage */ close_SSL(conn); return PGRES_POLLING_FAILED; } } /* Begin or continue the actual handshake */ return open_client_SSL(conn); #else /* shouldn't get here */ return PGRES_POLLING_FAILED; #endif }
ssize_t pqsecure_read | ( | PGconn * | , | |
void * | ptr, | |||
size_t | len | |||
) |
Definition at line 310 of file fe-secure.c.
References DECLARE_SIGPIPE_INFO, DISABLE_SIGPIPE, EAGAIN, ECONNRESET, EINTR, pg_conn::errorMessage, EWOULDBLOCK, libpq_gettext, printfPQExpBuffer(), recv, REMEMBER_EPIPE, RESTORE_SIGPIPE, pg_conn::sock, SOCK_ERRNO_SET, and SOCK_STRERROR.
Referenced by pqReadData().
{ ssize_t n; int result_errno = 0; char sebuf[256]; #ifdef USE_SSL if (conn->ssl) { int err; DECLARE_SIGPIPE_INFO(spinfo); /* SSL_read can write to the socket, so we need to disable SIGPIPE */ DISABLE_SIGPIPE(conn, spinfo, return -1); rloop: SOCK_ERRNO_SET(0); n = SSL_read(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); switch (err) { case SSL_ERROR_NONE: if (n < 0) { /* Not supposed to happen, so we don't translate the msg */ printfPQExpBuffer(&conn->errorMessage, "SSL_read failed but did not provide error information\n"); /* assume the connection is broken */ result_errno = ECONNRESET; } break; case SSL_ERROR_WANT_READ: n = 0; break; case SSL_ERROR_WANT_WRITE: /* * Returning 0 here would cause caller to wait for read-ready, * which is not correct since what SSL wants is wait for * write-ready. The former could get us stuck in an infinite * wait, so don't risk it; busy-loop instead. */ goto rloop; case SSL_ERROR_SYSCALL: if (n < 0) { result_errno = SOCK_ERRNO; REMEMBER_EPIPE(spinfo, result_errno == EPIPE); if (result_errno == EPIPE || result_errno == ECONNRESET) printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); } else { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: { char *errm = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); SSLerrfree(errm); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } case SSL_ERROR_ZERO_RETURN: /* * Per OpenSSL documentation, this error code is only returned * for a clean connection closure, so we should not report it * as a server crash. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL connection has been closed unexpectedly\n")); result_errno = ECONNRESET; n = -1; break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } RESTORE_SIGPIPE(conn, spinfo); } else #endif /* USE_SSL */ { n = recv(conn->sock, ptr, len, 0); if (n < 0) { result_errno = SOCK_ERRNO; /* Set error message if appropriate */ switch (result_errno) { #ifdef EAGAIN case EAGAIN: #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif case EINTR: /* no error message, caller is expected to retry */ break; #ifdef ECONNRESET case ECONNRESET: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); break; #endif default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); break; } } } /* ensure we return the intended errno to caller */ SOCK_ERRNO_SET(result_errno); return n; }
ssize_t pqsecure_write | ( | PGconn * | , | |
const void * | ptr, | |||
size_t | len | |||
) |
Definition at line 473 of file fe-secure.c.
References DECLARE_SIGPIPE_INFO, DISABLE_SIGPIPE, EAGAIN, ECONNRESET, EINTR, pg_conn::errorMessage, EWOULDBLOCK, libpq_gettext, printfPQExpBuffer(), REMEMBER_EPIPE, RESTORE_SIGPIPE, send, pg_conn::sigpipe_flag, pg_conn::sock, SOCK_ERRNO_SET, and SOCK_STRERROR.
Referenced by pqSendSome().
{ ssize_t n; int result_errno = 0; char sebuf[256]; DECLARE_SIGPIPE_INFO(spinfo); #ifdef USE_SSL if (conn->ssl) { int err; DISABLE_SIGPIPE(conn, spinfo, return -1); SOCK_ERRNO_SET(0); n = SSL_write(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); switch (err) { case SSL_ERROR_NONE: if (n < 0) { /* Not supposed to happen, so we don't translate the msg */ printfPQExpBuffer(&conn->errorMessage, "SSL_write failed but did not provide error information\n"); /* assume the connection is broken */ result_errno = ECONNRESET; } break; case SSL_ERROR_WANT_READ: /* * Returning 0 here causes caller to wait for write-ready, * which is not really the right thing, but it's the best we * can do. */ n = 0; break; case SSL_ERROR_WANT_WRITE: n = 0; break; case SSL_ERROR_SYSCALL: if (n < 0) { result_errno = SOCK_ERRNO; REMEMBER_EPIPE(spinfo, result_errno == EPIPE); if (result_errno == EPIPE || result_errno == ECONNRESET) printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); } else { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: { char *errm = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); SSLerrfree(errm); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } case SSL_ERROR_ZERO_RETURN: /* * Per OpenSSL documentation, this error code is only returned * for a clean connection closure, so we should not report it * as a server crash. */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL connection has been closed unexpectedly\n")); result_errno = ECONNRESET; n = -1; break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } } else #endif /* USE_SSL */ { int flags = 0; #ifdef MSG_NOSIGNAL if (conn->sigpipe_flag) flags |= MSG_NOSIGNAL; retry_masked: #endif /* MSG_NOSIGNAL */ DISABLE_SIGPIPE(conn, spinfo, return -1); n = send(conn->sock, ptr, len, flags); if (n < 0) { result_errno = SOCK_ERRNO; /* * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't * available on this machine. So, clear sigpipe_flag so we don't * try the flag again, and retry the send(). */ #ifdef MSG_NOSIGNAL if (flags != 0 && result_errno == EINVAL) { conn->sigpipe_flag = false; flags = 0; goto retry_masked; } #endif /* MSG_NOSIGNAL */ /* Set error message if appropriate */ switch (result_errno) { #ifdef EAGAIN case EAGAIN: #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif case EINTR: /* no error message, caller is expected to retry */ break; case EPIPE: /* Set flag for EPIPE */ REMEMBER_EPIPE(spinfo, true); /* FALL THRU */ #ifdef ECONNRESET case ECONNRESET: #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); break; } } } RESTORE_SIGPIPE(conn, spinfo); /* ensure we return the intended errno to caller */ SOCK_ERRNO_SET(result_errno); return n; }
PostgresPollingStatusType pqSetenvPoll | ( | PGconn * | conn | ) |
Definition at line 50 of file fe-protocol2.c.
References pg_conn::client_encoding_initial, CONNECTION_BAD, PQEnvironmentOption::envName, pg_conn::errorMessage, libpq_gettext, pg_conn::next_eo, NULL, pg_strcasecmp(), PQEnvironmentOption::pgName, PGRES_COMMAND_OK, PGRES_TUPLES_OK, PQclear(), PQgetResult(), PQgetvalue(), PQisBusy(), PQntuples(), pqReadData(), PQresultStatus(), pqSaveParameterStatus(), PQsendQuery(), printfPQExpBuffer(), pg_conn::setenv_state, SETENV_STATE_CLIENT_ENCODING_SEND, SETENV_STATE_CLIENT_ENCODING_WAIT, SETENV_STATE_IDLE, SETENV_STATE_OPTION_SEND, SETENV_STATE_OPTION_WAIT, SETENV_STATE_QUERY1_SEND, SETENV_STATE_QUERY1_WAIT, SETENV_STATE_QUERY2_SEND, SETENV_STATE_QUERY2_WAIT, pg_conn::status, pg_conn::sversion, and val.
Referenced by PQconnectPoll().
{ PGresult *res; if (conn == NULL || conn->status == CONNECTION_BAD) return PGRES_POLLING_FAILED; /* Check whether there are any data for us */ switch (conn->setenv_state) { /* These are reading states */ case SETENV_STATE_CLIENT_ENCODING_WAIT: case SETENV_STATE_OPTION_WAIT: case SETENV_STATE_QUERY1_WAIT: case SETENV_STATE_QUERY2_WAIT: { /* Load waiting data */ int n = pqReadData(conn); if (n < 0) goto error_return; if (n == 0) return PGRES_POLLING_READING; break; } /* These are writing states, so we just proceed. */ case SETENV_STATE_CLIENT_ENCODING_SEND: case SETENV_STATE_OPTION_SEND: case SETENV_STATE_QUERY1_SEND: case SETENV_STATE_QUERY2_SEND: break; /* Should we raise an error if called when not active? */ case SETENV_STATE_IDLE: return PGRES_POLLING_OK; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "invalid setenv state %c, " "probably indicative of memory corruption\n" ), conn->setenv_state); goto error_return; } /* We will loop here until there is nothing left to do in this call. */ for (;;) { switch (conn->setenv_state) { /* * The _CLIENT_ENCODING_SEND code is slightly different from * _OPTION_SEND below (e.g., no getenv() call), which is why a * different state is used. */ case SETENV_STATE_CLIENT_ENCODING_SEND: { char setQuery[100]; /* note length limit in * sprintf below */ const char *val = conn->client_encoding_initial; if (val) { if (pg_strcasecmp(val, "default") == 0) sprintf(setQuery, "SET client_encoding = DEFAULT"); else sprintf(setQuery, "SET client_encoding = '%.60s'", val); #ifdef CONNECTDEBUG fprintf(stderr, "Sending client_encoding with %s\n", setQuery); #endif if (!PQsendQuery(conn, setQuery)) goto error_return; conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_WAIT; } else conn->setenv_state = SETENV_STATE_OPTION_SEND; break; } case SETENV_STATE_OPTION_SEND: { /* * Send SET commands for stuff directed by Environment * Options. Note: we assume that SET commands won't start * transaction blocks, even in a 7.3 server with * autocommit off. */ char setQuery[100]; /* note length limit in * sprintf below */ if (conn->next_eo->envName) { const char *val; if ((val = getenv(conn->next_eo->envName))) { if (pg_strcasecmp(val, "default") == 0) sprintf(setQuery, "SET %s = DEFAULT", conn->next_eo->pgName); else sprintf(setQuery, "SET %s = '%.60s'", conn->next_eo->pgName, val); #ifdef CONNECTDEBUG fprintf(stderr, "Use environment variable %s to send %s\n", conn->next_eo->envName, setQuery); #endif if (!PQsendQuery(conn, setQuery)) goto error_return; conn->setenv_state = SETENV_STATE_OPTION_WAIT; } else conn->next_eo++; } else { /* No more options to send, so move on to querying */ conn->setenv_state = SETENV_STATE_QUERY1_SEND; } break; } case SETENV_STATE_CLIENT_ENCODING_WAIT: { if (PQisBusy(conn)) return PGRES_POLLING_READING; res = PQgetResult(conn); if (res) { if (PQresultStatus(res) != PGRES_COMMAND_OK) { PQclear(res); goto error_return; } PQclear(res); /* Keep reading until PQgetResult returns NULL */ } else { /* Query finished, so send the next option */ conn->setenv_state = SETENV_STATE_OPTION_SEND; } break; } case SETENV_STATE_OPTION_WAIT: { if (PQisBusy(conn)) return PGRES_POLLING_READING; res = PQgetResult(conn); if (res) { if (PQresultStatus(res) != PGRES_COMMAND_OK) { PQclear(res); goto error_return; } PQclear(res); /* Keep reading until PQgetResult returns NULL */ } else { /* Query finished, so send the next option */ conn->next_eo++; conn->setenv_state = SETENV_STATE_OPTION_SEND; } break; } case SETENV_STATE_QUERY1_SEND: { /* * Issue query to get information we need. Here we must * use begin/commit in case autocommit is off by default * in a 7.3 server. * * Note: version() exists in all protocol-2.0-supporting * backends. In 7.3 it would be safer to write * pg_catalog.version(), but we can't do that without * causing problems on older versions. */ if (!PQsendQuery(conn, "begin; select version(); end")) goto error_return; conn->setenv_state = SETENV_STATE_QUERY1_WAIT; return PGRES_POLLING_READING; } case SETENV_STATE_QUERY1_WAIT: { if (PQisBusy(conn)) return PGRES_POLLING_READING; res = PQgetResult(conn); if (res) { char *val; if (PQresultStatus(res) == PGRES_COMMAND_OK) { /* ignore begin/commit command results */ PQclear(res); continue; } if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) { PQclear(res); goto error_return; } /* * Extract server version and save as if * ParameterStatus */ val = PQgetvalue(res, 0, 0); if (val && strncmp(val, "PostgreSQL ", 11) == 0) { char *ptr; /* strip off PostgreSQL part */ val += 11; /* * strip off platform part (scribbles on result, * naughty naughty) */ ptr = strchr(val, ' '); if (ptr) *ptr = '\0'; pqSaveParameterStatus(conn, "server_version", val); } PQclear(res); /* Keep reading until PQgetResult returns NULL */ } else { /* Query finished, move to next */ conn->setenv_state = SETENV_STATE_QUERY2_SEND; } break; } case SETENV_STATE_QUERY2_SEND: { const char *query; /* * pg_client_encoding does not exist in pre-7.2 servers. * So we need to be prepared for an error here. Do *not* * start a transaction block, except in 7.3 servers where * we need to prevent autocommit-off from starting a * transaction anyway. */ if (conn->sversion >= 70300 && conn->sversion < 70400) query = "begin; select pg_catalog.pg_client_encoding(); end"; else query = "select pg_client_encoding()"; if (!PQsendQuery(conn, query)) goto error_return; conn->setenv_state = SETENV_STATE_QUERY2_WAIT; return PGRES_POLLING_READING; } case SETENV_STATE_QUERY2_WAIT: { if (PQisBusy(conn)) return PGRES_POLLING_READING; res = PQgetResult(conn); if (res) { const char *val; if (PQresultStatus(res) == PGRES_COMMAND_OK) { /* ignore begin/commit command results */ PQclear(res); continue; } if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1) { /* Extract client encoding and save it */ val = PQgetvalue(res, 0, 0); if (val && *val) /* null should not happen, but */ pqSaveParameterStatus(conn, "client_encoding", val); } else { /* * Error: presumably function not available, so * use PGCLIENTENCODING or SQL_ASCII as the * fallback. */ val = getenv("PGCLIENTENCODING"); if (val && *val) pqSaveParameterStatus(conn, "client_encoding", val); else pqSaveParameterStatus(conn, "client_encoding", "SQL_ASCII"); } PQclear(res); /* Keep reading until PQgetResult returns NULL */ } else { /* Query finished, so we're done */ conn->setenv_state = SETENV_STATE_IDLE; return PGRES_POLLING_OK; } break; } default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid state %c, " "probably indicative of memory corruption\n"), conn->setenv_state); goto error_return; } } /* Unreachable */ error_return: conn->setenv_state = SETENV_STATE_IDLE; return PGRES_POLLING_FAILED; }
void pqSetResultError | ( | PGresult * | res, | |
const char * | msg | |||
) |
Definition at line 614 of file fe-exec.c.
References pg_result::errMsg, and pqResultStrdup().
Referenced by pqCatenateResultError(), PQgetResult(), and PQmakeEmptyPGresult().
{ if (!res) return; if (msg && *msg) res->errMsg = pqResultStrdup(res, msg); else res->errMsg = NULL; }
int pqSkipnchar | ( | size_t | len, | |
PGconn * | conn | |||
) |
Definition at line 229 of file fe-misc.c.
References fputnbytes(), pg_conn::inBuffer, pg_conn::inCursor, pg_conn::inEnd, and pg_conn::Pfdebug.
Referenced by getAnotherTuple().
int pqWait | ( | int | forRead, | |
int | forWrite, | |||
PGconn * | conn | |||
) |
Definition at line 943 of file fe-misc.c.
References pqWaitTimed().
Referenced by pqFunctionCall2(), pqFunctionCall3(), pqGetCopyData2(), pqGetCopyData3(), pqGetline2(), pqGetline3(), PQgetResult(), and pqSendSome().
{ return pqWaitTimed(forRead, forWrite, conn, (time_t) -1); }
int pqWaitTimed | ( | int | forRead, | |
int | forWrite, | |||
PGconn * | conn, | |||
time_t | finish_time | |||
) |
Definition at line 958 of file fe-misc.c.
References pg_conn::errorMessage, libpq_gettext, pqSocketCheck(), and printfPQExpBuffer().
Referenced by connectDBComplete(), and pqWait().
{ int result; result = pqSocketCheck(conn, forRead, forWrite, finish_time); if (result < 0) return EOF; /* errorMessage is already set */ if (result == 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("timeout expired\n")); return EOF; } return 0; }
int pqWriteReady | ( | PGconn * | conn | ) |
Definition at line 992 of file fe-misc.c.
References pqSocketCheck().
{ return pqSocketCheck(conn, 0, 1, (time_t) 0); }
char* const pgresStatus[] |
Definition at line 32 of file fe-exec.c.
Referenced by PQresStatus().