Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
fe-protocol3.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include "libpq-fe.h"
#include "libpq-int.h"
#include "mb/pg_wchar.h"
#include "port/pg_bswap.h"
Include dependency graph for fe-protocol3.c:

Go to the source code of this file.

Macros

#define VALID_LONG_MESSAGE_TYPE(id)
 
#define DISPLAY_SIZE   60 /* screen width limit, in screen cols */
 
#define MIN_RIGHT_CUT   10 /* try to keep this far away from EOL */
 
#define ADD_STARTUP_OPTION(optname, optval)
 

Functions

static void handleFatalError (PGconn *conn)
 
static void handleSyncLoss (PGconn *conn, char id, int msgLength)
 
static int getRowDescriptions (PGconn *conn, int msgLength)
 
static int getParamDescriptions (PGconn *conn, int msgLength)
 
static int getAnotherTuple (PGconn *conn, int msgLength)
 
static int getParameterStatus (PGconn *conn)
 
static int getBackendKeyData (PGconn *conn, int msgLength)
 
static int getNotify (PGconn *conn)
 
static int getCopyStart (PGconn *conn, ExecStatusType copytype)
 
static int getReadyForQuery (PGconn *conn)
 
static void reportErrorPosition (PQExpBuffer msg, const char *query, int loc, int encoding)
 
static int build_startup_packet (const PGconn *conn, char *packet, const PQEnvironmentOption *options)
 
void pqParseInput3 (PGconn *conn)
 
int pqGetErrorNotice3 (PGconn *conn, bool isError)
 
void pqBuildErrorMessage3 (PQExpBuffer msg, const PGresult *res, PGVerbosity verbosity, PGContextVisibility show_context)
 
int pqGetNegotiateProtocolVersion3 (PGconn *conn)
 
static int getCopyDataMessage (PGconn *conn)
 
int pqGetCopyData3 (PGconn *conn, char **buffer, int async)
 
int pqGetline3 (PGconn *conn, char *s, int maxlen)
 
int pqGetlineAsync3 (PGconn *conn, char *buffer, int bufsize)
 
int pqEndcopy3 (PGconn *conn)
 
PGresultpqFunctionCall3 (PGconn *conn, Oid fnid, int *result_buf, int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs)
 
char * pqBuildStartupPacket3 (PGconn *conn, int *packetlen, const PQEnvironmentOption *options)
 

Macro Definition Documentation

◆ ADD_STARTUP_OPTION

#define ADD_STARTUP_OPTION (   optname,
  optval 
)
Value:
do { \
if (packet) \
strcpy(packet + packet_len, optname); \
packet_len += strlen(optname) + 1; \
if (packet) \
strcpy(packet + packet_len, optval); \
packet_len += strlen(optval) + 1; \
} while(0)

◆ DISPLAY_SIZE

#define DISPLAY_SIZE   60 /* screen width limit, in screen cols */

◆ MIN_RIGHT_CUT

#define MIN_RIGHT_CUT   10 /* try to keep this far away from EOL */

◆ VALID_LONG_MESSAGE_TYPE

#define VALID_LONG_MESSAGE_TYPE (   id)
Value:
((id) == PqMsg_CopyData || \
(id) == PqMsg_DataRow || \
(id) == PqMsg_ErrorResponse || \
(id) == PqMsg_NoticeResponse || \
#define PqMsg_NotificationResponse
Definition: protocol.h:41
#define PqMsg_CopyData
Definition: protocol.h:65
#define PqMsg_FunctionCallResponse
Definition: protocol.h:53
#define PqMsg_RowDescription
Definition: protocol.h:52
#define PqMsg_ErrorResponse
Definition: protocol.h:44
#define PqMsg_DataRow
Definition: protocol.h:43
#define PqMsg_NoticeResponse
Definition: protocol.h:49

Definition at line 36 of file fe-protocol3.c.

Function Documentation

◆ build_startup_packet()

static int build_startup_packet ( const PGconn conn,
char *  packet,
const PQEnvironmentOption options 
)
static

Definition at line 2395 of file fe-protocol3.c.

2397{
2398 int packet_len = 0;
2399 const PQEnvironmentOption *next_eo;
2400 const char *val;
2401
2402 /* Protocol version comes first. */
2403 if (packet)
2404 {
2406
2407 memcpy(packet + packet_len, &pv, sizeof(ProtocolVersion));
2408 }
2409 packet_len += sizeof(ProtocolVersion);
2410
2411 /* Add user name, database name, options */
2412
2413#define ADD_STARTUP_OPTION(optname, optval) \
2414 do { \
2415 if (packet) \
2416 strcpy(packet + packet_len, optname); \
2417 packet_len += strlen(optname) + 1; \
2418 if (packet) \
2419 strcpy(packet + packet_len, optval); \
2420 packet_len += strlen(optval) + 1; \
2421 } while(0)
2422
2423 if (conn->pguser && conn->pguser[0])
2424 ADD_STARTUP_OPTION("user", conn->pguser);
2425 if (conn->dbName && conn->dbName[0])
2426 ADD_STARTUP_OPTION("database", conn->dbName);
2427 if (conn->replication && conn->replication[0])
2428 ADD_STARTUP_OPTION("replication", conn->replication);
2429 if (conn->pgoptions && conn->pgoptions[0])
2430 ADD_STARTUP_OPTION("options", conn->pgoptions);
2431 if (conn->send_appname)
2432 {
2433 /* Use appname if present, otherwise use fallback */
2435 if (val && val[0])
2436 ADD_STARTUP_OPTION("application_name", val);
2437 }
2438
2440 ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial);
2441
2442 /* Add any environment-driven GUC settings needed */
2443 for (next_eo = options; next_eo->envName; next_eo++)
2444 {
2445 if ((val = getenv(next_eo->envName)) != NULL)
2446 {
2447 if (pg_strcasecmp(val, "default") != 0)
2448 ADD_STARTUP_OPTION(next_eo->pgName, val);
2449 }
2450 }
2451
2452 /* Add trailing terminator */
2453 if (packet)
2454 packet[packet_len] = '\0';
2455 packet_len++;
2456
2457 return packet_len;
2458}
#define ADD_STARTUP_OPTION(optname, optval)
long val
Definition: informix.c:689
#define pg_hton32(x)
Definition: pg_bswap.h:121
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
uint32 ProtocolVersion
Definition: pqcomm.h:99
PGconn * conn
Definition: streamutil.c:52
const char * pgName
Definition: libpq-int.h:265
const char * envName
Definition: libpq-int.h:264
char * replication
Definition: libpq-int.h:391
ProtocolVersion pversion
Definition: libpq-int.h:503
char * pgoptions
Definition: libpq-int.h:387
bool send_appname
Definition: libpq-int.h:543
char * dbName
Definition: libpq-int.h:390
char * fbappname
Definition: libpq-int.h:389
char * pguser
Definition: libpq-int.h:395
char * client_encoding_initial
Definition: libpq-int.h:386
char * appname
Definition: libpq-int.h:388

References ADD_STARTUP_OPTION, pg_conn::appname, pg_conn::client_encoding_initial, conn, pg_conn::dbName, PQEnvironmentOption::envName, pg_conn::fbappname, pg_hton32, pg_strcasecmp(), PQEnvironmentOption::pgName, pg_conn::pgoptions, pg_conn::pguser, pg_conn::pversion, pg_conn::replication, pg_conn::send_appname, and val.

Referenced by pqBuildStartupPacket3().

◆ getAnotherTuple()

static int getAnotherTuple ( PGconn conn,
int  msgLength 
)
static

Definition at line 775 of file fe-protocol3.c.

776{
777 PGresult *result = conn->result;
778 int nfields = result->numAttributes;
779 const char *errmsg;
780 PGdataValue *rowbuf;
781 int tupnfields; /* # fields from tuple */
782 int vlen; /* length of the current field value */
783 int i;
784
785 /* Get the field count and make sure it's what we expect */
786 if (pqGetInt(&tupnfields, 2, conn))
787 {
788 /* We should not run out of data here, so complain */
789 errmsg = libpq_gettext("insufficient data in \"D\" message");
790 goto advance_and_error;
791 }
792
793 if (tupnfields != nfields)
794 {
795 errmsg = libpq_gettext("unexpected field count in \"D\" message");
796 goto advance_and_error;
797 }
798
799 /* Resize row buffer if needed */
800 rowbuf = conn->rowBuf;
801 if (nfields > conn->rowBufLen)
802 {
803 rowbuf = (PGdataValue *) realloc(rowbuf,
804 nfields * sizeof(PGdataValue));
805 if (!rowbuf)
806 {
807 errmsg = NULL; /* means "out of memory", see below */
808 goto advance_and_error;
809 }
810 conn->rowBuf = rowbuf;
811 conn->rowBufLen = nfields;
812 }
813
814 /* Scan the fields */
815 for (i = 0; i < nfields; i++)
816 {
817 /* get the value length */
818 if (pqGetInt(&vlen, 4, conn))
819 {
820 /* We should not run out of data here, so complain */
821 errmsg = libpq_gettext("insufficient data in \"D\" message");
822 goto advance_and_error;
823 }
824 rowbuf[i].len = vlen;
825
826 /*
827 * rowbuf[i].value always points to the next address in the data
828 * buffer even if the value is NULL. This allows row processors to
829 * estimate data sizes more easily.
830 */
831 rowbuf[i].value = conn->inBuffer + conn->inCursor;
832
833 /* Skip over the data value */
834 if (vlen > 0)
835 {
836 if (pqSkipnchar(vlen, conn))
837 {
838 /* We should not run out of data here, so complain */
839 errmsg = libpq_gettext("insufficient data in \"D\" message");
840 goto advance_and_error;
841 }
842 }
843 }
844
845 /* Process the collected row */
846 errmsg = NULL;
848 return 0; /* normal, successful exit */
849
850 /* pqRowProcessor failed, fall through to report it */
851
852advance_and_error:
853
854 /*
855 * Replace partially constructed result with an error result. First
856 * discard the old result to try to win back some memory.
857 */
859
860 /*
861 * If preceding code didn't provide an error message, assume "out of
862 * memory" was meant. The advantage of having this special case is that
863 * freeing the old result first greatly improves the odds that gettext()
864 * will succeed in providing a translation.
865 */
866 if (!errmsg)
867 errmsg = libpq_gettext("out of memory for query result");
868
871
872 /*
873 * Show the message as fully consumed, else pqParseInput3 will overwrite
874 * our error with a complaint about that.
875 */
876 conn->inCursor = conn->inStart + 5 + msgLength;
877
878 /*
879 * Return zero to allow input parsing to continue. Subsequent "D"
880 * messages will be ignored until we get to end of data, since an error
881 * result is already set up.
882 */
883 return 0;
884}
int errmsg(const char *fmt,...)
Definition: elog.c:1071
void pqSaveErrorResult(PGconn *conn)
Definition: fe-exec.c:803
int pqRowProcessor(PGconn *conn, const char **errmsgp)
Definition: fe-exec.c:1217
void pqClearAsyncResult(PGconn *conn)
Definition: fe-exec.c:779
int pqSkipnchar(size_t len, PGconn *conn)
Definition: fe-misc.c:187
int pqGetInt(int *result, size_t bytes, PGconn *conn)
Definition: fe-misc.c:216
#define realloc(a, b)
Definition: header.h:60
int i
Definition: isn.c:77
#define libpq_gettext(x)
Definition: oauth-utils.h:86
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
const char * value
Definition: libpq-int.h:303
PGdataValue * rowBuf
Definition: libpq-int.h:584
char * inBuffer
Definition: libpq-int.h:567
int inCursor
Definition: libpq-int.h:570
int inStart
Definition: libpq-int.h:569
PGresult * result
Definition: libpq-int.h:597
PQExpBufferData errorMessage
Definition: libpq-int.h:674
int rowBufLen
Definition: libpq-int.h:585
int numAttributes
Definition: libpq-int.h:167

References appendPQExpBuffer(), conn, errmsg(), pg_conn::errorMessage, i, pg_conn::inBuffer, pg_conn::inCursor, pg_conn::inStart, pgDataValue::len, libpq_gettext, pg_result::numAttributes, pqClearAsyncResult(), pqGetInt(), pqRowProcessor(), pqSaveErrorResult(), pqSkipnchar(), realloc, pg_conn::result, pg_conn::rowBuf, pg_conn::rowBufLen, and pgDataValue::value.

Referenced by pqParseInput3().

◆ getBackendKeyData()

static int getBackendKeyData ( PGconn conn,
int  msgLength 
)
static

Definition at line 1556 of file fe-protocol3.c.

1557{
1558 int cancel_key_len;
1559
1560 if (conn->be_cancel_key)
1561 {
1563 conn->be_cancel_key = NULL;
1565 }
1566
1567 if (pqGetInt(&(conn->be_pid), 4, conn))
1568 return EOF;
1569
1570 cancel_key_len = 5 + msgLength - (conn->inCursor - conn->inStart);
1571
1572 if (cancel_key_len != 4 && conn->pversion == PG_PROTOCOL(3, 0))
1573 {
1574 libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d not allowed in protocol version 3.0 (must be 4 bytes)", cancel_key_len);
1576 return 0;
1577 }
1578
1579 if (cancel_key_len < 4)
1580 {
1581 libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d is too short (minimum 4 bytes)", cancel_key_len);
1583 return 0;
1584 }
1585
1586 if (cancel_key_len > 256)
1587 {
1588 libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d is too long (maximum 256 bytes)", cancel_key_len);
1590 return 0;
1591 }
1592
1593 conn->be_cancel_key = malloc(cancel_key_len);
1594 if (conn->be_cancel_key == NULL)
1595 {
1596 libpq_append_conn_error(conn, "out of memory");
1598 return 0;
1599 }
1600 if (pqGetnchar(conn->be_cancel_key, cancel_key_len, conn))
1601 {
1603 conn->be_cancel_key = NULL;
1604 return EOF;
1605 }
1606 conn->be_cancel_key_len = cancel_key_len;
1607 return 0;
1608}
int pqGetnchar(void *s, size_t len, PGconn *conn)
Definition: fe-misc.c:165
static void handleFatalError(PGconn *conn)
Definition: fe-protocol3.c:485
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
Definition: oauth-utils.c:95
#define PG_PROTOCOL(m, n)
Definition: pqcomm.h:90
uint8 * be_cancel_key
Definition: libpq-int.h:554
int be_pid
Definition: libpq-int.h:552
int be_cancel_key_len
Definition: libpq-int.h:553

References pg_conn::be_cancel_key, pg_conn::be_cancel_key_len, pg_conn::be_pid, conn, free, handleFatalError(), pg_conn::inCursor, pg_conn::inStart, libpq_append_conn_error(), malloc, PG_PROTOCOL, pqGetInt(), pqGetnchar(), and pg_conn::pversion.

Referenced by pqParseInput3().

◆ getCopyDataMessage()

static int getCopyDataMessage ( PGconn conn)
static

Definition at line 1779 of file fe-protocol3.c.

1780{
1781 char id;
1782 int msgLength;
1783 int avail;
1784
1785 for (;;)
1786 {
1787 /*
1788 * Do we have the next input message? To make life simpler for async
1789 * callers, we keep returning 0 until the next message is fully
1790 * available, even if it is not Copy Data.
1791 */
1793 if (pqGetc(&id, conn))
1794 return 0;
1795 if (pqGetInt(&msgLength, 4, conn))
1796 return 0;
1797 if (msgLength < 4)
1798 {
1799 handleSyncLoss(conn, id, msgLength);
1800 return -2;
1801 }
1802 avail = conn->inEnd - conn->inCursor;
1803 if (avail < msgLength - 4)
1804 {
1805 /*
1806 * Before returning, enlarge the input buffer if needed to hold
1807 * the whole message. See notes in parseInput.
1808 */
1809 if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength - 4,
1810 conn))
1811 {
1812 /*
1813 * Abandon the connection. There's not much else we can
1814 * safely do; we can't just ignore the message or we could
1815 * miss important changes to the connection state.
1816 * pqCheckInBufferSpace() already reported the error.
1817 */
1819 return -2;
1820 }
1821 return 0;
1822 }
1823
1824 /*
1825 * If it's a legitimate async message type, process it. (NOTIFY
1826 * messages are not currently possible here, but we handle them for
1827 * completeness.) Otherwise, if it's anything except Copy Data,
1828 * report end-of-copy.
1829 */
1830 switch (id)
1831 {
1833 if (getNotify(conn))
1834 return 0;
1835 break;
1837 if (pqGetErrorNotice3(conn, false))
1838 return 0;
1839 break;
1842 return 0;
1843 break;
1844 case PqMsg_CopyData:
1845 return msgLength;
1846 case PqMsg_CopyDone:
1847
1848 /*
1849 * If this is a CopyDone message, exit COPY_OUT mode and let
1850 * caller read status with PQgetResult(). If we're in
1851 * COPY_BOTH mode, return to COPY_IN mode.
1852 */
1855 else
1857 return -1;
1858 default: /* treat as end of copy */
1859
1860 /*
1861 * Any other message terminates either COPY_IN or COPY_BOTH
1862 * mode.
1863 */
1865 return -1;
1866 }
1867
1868 /* Drop the processed message and loop around for another */
1870 }
1871}
void pqParseDone(PGconn *conn, int newInStart)
Definition: fe-misc.c:443
int pqGetc(char *result, PGconn *conn)
Definition: fe-misc.c:77
int pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
Definition: fe-misc.c:351
static int getNotify(PGconn *conn)
static int getParameterStatus(PGconn *conn)
static void handleSyncLoss(PGconn *conn, char id, int msgLength)
Definition: fe-protocol3.c:501
int pqGetErrorNotice3(PGconn *conn, bool isError)
Definition: fe-protocol3.c:896
@ PGASYNC_COPY_BOTH
Definition: libpq-int.h:224
@ PGASYNC_COPY_IN
Definition: libpq-int.h:222
@ PGASYNC_BUSY
Definition: libpq-int.h:216
#define PqMsg_CopyDone
Definition: protocol.h:64
#define PqMsg_ParameterStatus
Definition: protocol.h:51
int inEnd
Definition: libpq-int.h:571
PGAsyncStatusType asyncStatus
Definition: libpq-int.h:463

References pg_conn::asyncStatus, conn, getNotify(), getParameterStatus(), handleFatalError(), handleSyncLoss(), pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, PGASYNC_BUSY, PGASYNC_COPY_BOTH, PGASYNC_COPY_IN, pqCheckInBufferSpace(), pqGetc(), pqGetErrorNotice3(), pqGetInt(), PqMsg_CopyData, PqMsg_CopyDone, PqMsg_NoticeResponse, PqMsg_NotificationResponse, PqMsg_ParameterStatus, and pqParseDone().

Referenced by pqGetCopyData3(), and pqGetlineAsync3().

◆ getCopyStart()

static int getCopyStart ( PGconn conn,
ExecStatusType  copytype 
)
static

Definition at line 1691 of file fe-protocol3.c.

1692{
1693 PGresult *result;
1694 int nfields;
1695 int i;
1696
1697 result = PQmakeEmptyPGresult(conn, copytype);
1698 if (!result)
1699 goto failure;
1700
1702 goto failure;
1703 result->binary = conn->copy_is_binary;
1704 /* the next two bytes are the number of fields */
1705 if (pqGetInt(&(result->numAttributes), 2, conn))
1706 goto failure;
1707 nfields = result->numAttributes;
1708
1709 /* allocate space for the attribute descriptors */
1710 if (nfields > 0)
1711 {
1712 result->attDescs = (PGresAttDesc *)
1713 pqResultAlloc(result, nfields * sizeof(PGresAttDesc), true);
1714 if (!result->attDescs)
1715 goto failure;
1716 MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
1717 }
1718
1719 for (i = 0; i < nfields; i++)
1720 {
1721 int format;
1722
1723 if (pqGetInt(&format, 2, conn))
1724 goto failure;
1725
1726 /*
1727 * Since pqGetInt treats 2-byte integers as unsigned, we need to
1728 * coerce these results to signed form.
1729 */
1730 format = (int) ((int16) format);
1731 result->attDescs[i].format = format;
1732 }
1733
1734 /* Success! */
1735 conn->result = result;
1736 return 0;
1737
1738failure:
1739 PQclear(result);
1740 return EOF;
1741}
int16_t int16
Definition: c.h:534
#define MemSet(start, val, len)
Definition: c.h:1020
void * pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
Definition: fe-exec.c:563
PGresult * PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
Definition: fe-exec.c:159
#define PQclear
Definition: libpq-be-fe.h:245
static char format
char copy_is_binary
Definition: libpq-int.h:474
int binary
Definition: libpq-int.h:176
PGresAttDesc * attDescs
Definition: libpq-int.h:168

References pg_result::attDescs, pg_result::binary, conn, pg_conn::copy_is_binary, format, pgresAttDesc::format, i, MemSet, pg_result::numAttributes, PQclear, pqGetc(), pqGetInt(), PQmakeEmptyPGresult(), pqResultAlloc(), and pg_conn::result.

Referenced by pqParseInput3().

◆ getNotify()

static int getNotify ( PGconn conn)
static

Definition at line 1620 of file fe-protocol3.c.

1621{
1622 int be_pid;
1623 char *svname;
1624 int nmlen;
1625 int extralen;
1626 PGnotify *newNotify;
1627
1628 if (pqGetInt(&be_pid, 4, conn))
1629 return EOF;
1630 if (pqGets(&conn->workBuffer, conn))
1631 return EOF;
1632 /* must save name while getting extra string */
1633 svname = strdup(conn->workBuffer.data);
1634 if (!svname)
1635 {
1636 /*
1637 * Notify messages can arrive at any state, so we cannot associate the
1638 * error with any particular query. There's no way to return back an
1639 * "async error", so the best we can do is drop the connection. That
1640 * seems better than silently ignoring the notification.
1641 */
1642 libpq_append_conn_error(conn, "out of memory");
1644 return 0;
1645 }
1646 if (pqGets(&conn->workBuffer, conn))
1647 {
1648 free(svname);
1649 return EOF;
1650 }
1651
1652 /*
1653 * Store the strings right after the PGnotify structure so it can all be
1654 * freed at once. We don't use NAMEDATALEN because we don't want to tie
1655 * this interface to a specific server name length.
1656 */
1657 nmlen = strlen(svname);
1658 extralen = strlen(conn->workBuffer.data);
1659 newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + extralen + 2);
1660 if (!newNotify)
1661 {
1662 free(svname);
1663 libpq_append_conn_error(conn, "out of memory");
1665 return 0;
1666 }
1667
1668 newNotify->relname = (char *) newNotify + sizeof(PGnotify);
1669 strcpy(newNotify->relname, svname);
1670 newNotify->extra = newNotify->relname + nmlen + 1;
1671 strcpy(newNotify->extra, conn->workBuffer.data);
1672 newNotify->be_pid = be_pid;
1673 newNotify->next = NULL;
1674 if (conn->notifyTail)
1675 conn->notifyTail->next = newNotify;
1676 else
1677 conn->notifyHead = newNotify;
1678 conn->notifyTail = newNotify;
1679
1680 free(svname);
1681 return 0;
1682}
int pqGets(PQExpBuffer buf, PGconn *conn)
Definition: fe-misc.c:136
struct pgNotify * next
Definition: libpq-fe.h:234
int be_pid
Definition: libpq-fe.h:231
char * relname
Definition: libpq-fe.h:230
char * extra
Definition: libpq-fe.h:232
PGnotify * notifyHead
Definition: libpq-int.h:476
PGnotify * notifyTail
Definition: libpq-int.h:477
PQExpBufferData workBuffer
Definition: libpq-int.h:678

References pgNotify::be_pid, conn, PQExpBufferData::data, pgNotify::extra, free, handleFatalError(), libpq_append_conn_error(), malloc, pgNotify::next, pg_conn::notifyHead, pg_conn::notifyTail, pqGetInt(), pqGets(), pgNotify::relname, and pg_conn::workBuffer.

Referenced by getCopyDataMessage(), pqFunctionCall3(), and pqParseInput3().

◆ getParamDescriptions()

static int getParamDescriptions ( PGconn conn,
int  msgLength 
)
static

Definition at line 687 of file fe-protocol3.c.

688{
689 PGresult *result;
690 const char *errmsg = NULL; /* means "out of memory", see below */
691 int nparams;
692 int i;
693
695 if (!result)
696 goto advance_and_error;
697
698 /* parseInput already read the 't' label and message length. */
699 /* the next two bytes are the number of parameters */
700 if (pqGetInt(&(result->numParameters), 2, conn))
701 goto not_enough_data;
702 nparams = result->numParameters;
703
704 /* allocate space for the parameter descriptors */
705 if (nparams > 0)
706 {
707 result->paramDescs = (PGresParamDesc *)
708 pqResultAlloc(result, nparams * sizeof(PGresParamDesc), true);
709 if (!result->paramDescs)
710 goto advance_and_error;
711 MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc));
712 }
713
714 /* get parameter info */
715 for (i = 0; i < nparams; i++)
716 {
717 int typid;
718
719 if (pqGetInt(&typid, 4, conn))
720 goto not_enough_data;
721 result->paramDescs[i].typid = typid;
722 }
723
724 /* Success! */
725 conn->result = result;
726
727 return 0;
728
729not_enough_data:
730 errmsg = libpq_gettext("insufficient data in \"t\" message");
731
732advance_and_error:
733 /* Discard unsaved result, if any */
734 if (result && result != conn->result)
735 PQclear(result);
736
737 /*
738 * Replace partially constructed result with an error result. First
739 * discard the old result to try to win back some memory.
740 */
742
743 /*
744 * If preceding code didn't provide an error message, assume "out of
745 * memory" was meant. The advantage of having this special case is that
746 * freeing the old result first greatly improves the odds that gettext()
747 * will succeed in providing a translation.
748 */
749 if (!errmsg)
750 errmsg = libpq_gettext("out of memory");
753
754 /*
755 * Show the message as fully consumed, else pqParseInput3 will overwrite
756 * our error with a complaint about that.
757 */
758 conn->inCursor = conn->inStart + 5 + msgLength;
759
760 /*
761 * Return zero to allow input parsing to continue. Essentially, we've
762 * replaced the COMMAND_OK result with an error result, but since this
763 * doesn't affect the protocol state, it's fine.
764 */
765 return 0;
766}
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:125
int numParameters
Definition: libpq-int.h:172
PGresParamDesc * paramDescs
Definition: libpq-int.h:173

References appendPQExpBuffer(), conn, errmsg(), pg_conn::errorMessage, i, pg_conn::inCursor, pg_conn::inStart, libpq_gettext, MemSet, pg_result::numParameters, pg_result::paramDescs, PGRES_COMMAND_OK, PQclear, pqClearAsyncResult(), pqGetInt(), PQmakeEmptyPGresult(), pqResultAlloc(), pqSaveErrorResult(), pg_conn::result, and pgresParamDesc::typid.

Referenced by pqParseInput3().

◆ getParameterStatus()

static int getParameterStatus ( PGconn conn)
static

Definition at line 1525 of file fe-protocol3.c.

1526{
1527 PQExpBufferData valueBuf;
1528
1529 /* Get the parameter name */
1530 if (pqGets(&conn->workBuffer, conn))
1531 return EOF;
1532 /* Get the parameter value (could be large) */
1533 initPQExpBuffer(&valueBuf);
1534 if (pqGets(&valueBuf, conn))
1535 {
1536 termPQExpBuffer(&valueBuf);
1537 return EOF;
1538 }
1539 /* And save it */
1541 {
1542 libpq_append_conn_error(conn, "out of memory");
1544 }
1545 termPQExpBuffer(&valueBuf);
1546 return 0;
1547}
int pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
Definition: fe-exec.c:1085
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129

References conn, PQExpBufferData::data, handleFatalError(), initPQExpBuffer(), libpq_append_conn_error(), pqGets(), pqSaveParameterStatus(), termPQExpBuffer(), and pg_conn::workBuffer.

Referenced by getCopyDataMessage(), pqFunctionCall3(), and pqParseInput3().

◆ getReadyForQuery()

static int getReadyForQuery ( PGconn conn)
static

Definition at line 1747 of file fe-protocol3.c.

1748{
1749 char xact_status;
1750
1751 if (pqGetc(&xact_status, conn))
1752 return EOF;
1753 switch (xact_status)
1754 {
1755 case 'I':
1757 break;
1758 case 'T':
1760 break;
1761 case 'E':
1763 break;
1764 default:
1766 break;
1767 }
1768
1769 return 0;
1770}
@ PQTRANS_INTRANS
Definition: libpq-fe.h:149
@ PQTRANS_IDLE
Definition: libpq-fe.h:147
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:151
@ PQTRANS_INERROR
Definition: libpq-fe.h:150
PGTransactionStatusType xactStatus
Definition: libpq-int.h:464

References conn, pqGetc(), PQTRANS_IDLE, PQTRANS_INERROR, PQTRANS_INTRANS, PQTRANS_UNKNOWN, and pg_conn::xactStatus.

Referenced by pqFunctionCall3(), and pqParseInput3().

◆ getRowDescriptions()

static int getRowDescriptions ( PGconn conn,
int  msgLength 
)
static

Definition at line 516 of file fe-protocol3.c.

517{
518 PGresult *result;
519 int nfields;
520 const char *errmsg;
521 int i;
522
523 /*
524 * When doing Describe for a prepared statement, there'll already be a
525 * PGresult created by getParamDescriptions, and we should fill data into
526 * that. Otherwise, create a new, empty PGresult.
527 */
528 if (!conn->cmd_queue_head ||
531 {
532 if (conn->result)
533 result = conn->result;
534 else
536 }
537 else
539 if (!result)
540 {
541 errmsg = NULL; /* means "out of memory", see below */
542 goto advance_and_error;
543 }
544
545 /* parseInput already read the 'T' label and message length. */
546 /* the next two bytes are the number of fields */
547 if (pqGetInt(&(result->numAttributes), 2, conn))
548 {
549 /* We should not run out of data here, so complain */
550 errmsg = libpq_gettext("insufficient data in \"T\" message");
551 goto advance_and_error;
552 }
553 nfields = result->numAttributes;
554
555 /* allocate space for the attribute descriptors */
556 if (nfields > 0)
557 {
558 result->attDescs = (PGresAttDesc *)
559 pqResultAlloc(result, nfields * sizeof(PGresAttDesc), true);
560 if (!result->attDescs)
561 {
562 errmsg = NULL; /* means "out of memory", see below */
563 goto advance_and_error;
564 }
565 MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
566 }
567
568 /* result->binary is true only if ALL columns are binary */
569 result->binary = (nfields > 0) ? 1 : 0;
570
571 /* get type info */
572 for (i = 0; i < nfields; i++)
573 {
574 int tableid;
575 int columnid;
576 int typid;
577 int typlen;
578 int atttypmod;
579 int format;
580
581 if (pqGets(&conn->workBuffer, conn) ||
582 pqGetInt(&tableid, 4, conn) ||
583 pqGetInt(&columnid, 2, conn) ||
584 pqGetInt(&typid, 4, conn) ||
585 pqGetInt(&typlen, 2, conn) ||
586 pqGetInt(&atttypmod, 4, conn) ||
587 pqGetInt(&format, 2, conn))
588 {
589 /* We should not run out of data here, so complain */
590 errmsg = libpq_gettext("insufficient data in \"T\" message");
591 goto advance_and_error;
592 }
593
594 /*
595 * Since pqGetInt treats 2-byte integers as unsigned, we need to
596 * coerce these results to signed form.
597 */
598 columnid = (int) ((int16) columnid);
599 typlen = (int) ((int16) typlen);
600 format = (int) ((int16) format);
601
602 result->attDescs[i].name = pqResultStrdup(result,
604 if (!result->attDescs[i].name)
605 {
606 errmsg = NULL; /* means "out of memory", see below */
607 goto advance_and_error;
608 }
609 result->attDescs[i].tableid = tableid;
610 result->attDescs[i].columnid = columnid;
611 result->attDescs[i].format = format;
612 result->attDescs[i].typid = typid;
613 result->attDescs[i].typlen = typlen;
614 result->attDescs[i].atttypmod = atttypmod;
615
616 if (format != 1)
617 result->binary = 0;
618 }
619
620 /* Success! */
621 conn->result = result;
622
623 /*
624 * If we're doing a Describe, we're done, and ready to pass the result
625 * back to the client.
626 */
627 if ((!conn->cmd_queue_head) ||
630 {
632 return 0;
633 }
634
635 /*
636 * We could perform additional setup for the new result set here, but for
637 * now there's nothing else to do.
638 */
639
640 /* And we're done. */
641 return 0;
642
643advance_and_error:
644 /* Discard unsaved result, if any */
645 if (result && result != conn->result)
646 PQclear(result);
647
648 /*
649 * Replace partially constructed result with an error result. First
650 * discard the old result to try to win back some memory.
651 */
653
654 /*
655 * If preceding code didn't provide an error message, assume "out of
656 * memory" was meant. The advantage of having this special case is that
657 * freeing the old result first greatly improves the odds that gettext()
658 * will succeed in providing a translation.
659 */
660 if (!errmsg)
661 errmsg = libpq_gettext("out of memory for query result");
662
665
666 /*
667 * Show the message as fully consumed, else pqParseInput3 will overwrite
668 * our error with a complaint about that.
669 */
670 conn->inCursor = conn->inStart + 5 + msgLength;
671
672 /*
673 * Return zero to allow input parsing to continue. Subsequent "D"
674 * messages will be ignored until we get to end of data, since an error
675 * result is already set up.
676 */
677 return 0;
678}
char * pqResultStrdup(PGresult *res, const char *str)
Definition: fe-exec.c:675
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:128
@ PGASYNC_READY
Definition: libpq-int.h:217
@ PGQUERY_DESCRIBE
Definition: libpq-int.h:323
PGQueryClass queryclass
Definition: libpq-int.h:345
PGcmdQueueEntry * cmd_queue_head
Definition: libpq-int.h:489
char * name
Definition: libpq-fe.h:307
int columnid
Definition: libpq-fe.h:309
int atttypmod
Definition: libpq-fe.h:313

References appendPQExpBuffer(), pg_conn::asyncStatus, pg_result::attDescs, pgresAttDesc::atttypmod, pg_result::binary, pg_conn::cmd_queue_head, pgresAttDesc::columnid, conn, PQExpBufferData::data, errmsg(), pg_conn::errorMessage, format, pgresAttDesc::format, i, pg_conn::inCursor, pg_conn::inStart, libpq_gettext, MemSet, pgresAttDesc::name, pg_result::numAttributes, PGASYNC_READY, PGQUERY_DESCRIBE, PGRES_COMMAND_OK, PGRES_TUPLES_OK, PQclear, pqClearAsyncResult(), pqGetInt(), pqGets(), PQmakeEmptyPGresult(), pqResultAlloc(), pqResultStrdup(), pqSaveErrorResult(), PGcmdQueueEntry::queryclass, pg_conn::result, pgresAttDesc::tableid, pgresAttDesc::typid, pgresAttDesc::typlen, and pg_conn::workBuffer.

Referenced by pqParseInput3().

◆ handleFatalError()

static void handleFatalError ( PGconn conn)
static

Definition at line 485 of file fe-protocol3.c.

486{
487 /* build an error result holding the error message */
489 conn->asyncStatus = PGASYNC_READY; /* drop out of PQgetResult wait loop */
490 /* flush input data since we're giving up on processing it */
491 pqDropConnection(conn, true);
492 conn->status = CONNECTION_BAD; /* No more connection to backend */
493}
void pqDropConnection(PGconn *conn, bool flushInput)
Definition: fe-connect.c:530
@ CONNECTION_BAD
Definition: libpq-fe.h:85
ConnStatusType status
Definition: libpq-int.h:462

References pg_conn::asyncStatus, conn, CONNECTION_BAD, PGASYNC_READY, pqDropConnection(), pqSaveErrorResult(), and pg_conn::status.

Referenced by getBackendKeyData(), getCopyDataMessage(), getNotify(), getParameterStatus(), handleSyncLoss(), pqFunctionCall3(), and pqParseInput3().

◆ handleSyncLoss()

static void handleSyncLoss ( PGconn conn,
char  id,
int  msgLength 
)
static

Definition at line 501 of file fe-protocol3.c.

502{
503 libpq_append_conn_error(conn, "lost synchronization with server: got message type \"%c\", length %d",
504 id, msgLength);
506}

References conn, handleFatalError(), and libpq_append_conn_error().

Referenced by getCopyDataMessage(), pqFunctionCall3(), and pqParseInput3().

◆ pqBuildErrorMessage3()

void pqBuildErrorMessage3 ( PQExpBuffer  msg,
const PGresult res,
PGVerbosity  verbosity,
PGContextVisibility  show_context 
)

Definition at line 1028 of file fe-protocol3.c.

1030{
1031 const char *val;
1032 const char *querytext = NULL;
1033 int querypos = 0;
1034
1035 /* If we couldn't allocate a PGresult, just say "out of memory" */
1036 if (res == NULL)
1037 {
1038 appendPQExpBufferStr(msg, libpq_gettext("out of memory\n"));
1039 return;
1040 }
1041
1042 /*
1043 * If we don't have any broken-down fields, just return the base message.
1044 * This mainly applies if we're given a libpq-generated error result.
1045 */
1046 if (res->errFields == NULL)
1047 {
1048 if (res->errMsg && res->errMsg[0])
1049 appendPQExpBufferStr(msg, res->errMsg);
1050 else
1051 appendPQExpBufferStr(msg, libpq_gettext("no error message available\n"));
1052 return;
1053 }
1054
1055 /* Else build error message from relevant fields */
1057 if (val)
1058 appendPQExpBuffer(msg, "%s: ", val);
1059
1060 if (verbosity == PQERRORS_SQLSTATE)
1061 {
1062 /*
1063 * If we have a SQLSTATE, print that and nothing else. If not (which
1064 * shouldn't happen for server-generated errors, but might possibly
1065 * happen for libpq-generated ones), fall back to TERSE format, as
1066 * that seems better than printing nothing at all.
1067 */
1069 if (val)
1070 {
1071 appendPQExpBuffer(msg, "%s\n", val);
1072 return;
1073 }
1074 verbosity = PQERRORS_TERSE;
1075 }
1076
1077 if (verbosity == PQERRORS_VERBOSE)
1078 {
1080 if (val)
1081 appendPQExpBuffer(msg, "%s: ", val);
1082 }
1084 if (val)
1087 if (val)
1088 {
1089 if (verbosity != PQERRORS_TERSE && res->errQuery != NULL)
1090 {
1091 /* emit position as a syntax cursor display */
1092 querytext = res->errQuery;
1093 querypos = atoi(val);
1094 }
1095 else
1096 {
1097 /* emit position as text addition to primary message */
1098 /* translator: %s represents a digit string */
1099 appendPQExpBuffer(msg, libpq_gettext(" at character %s"),
1100 val);
1101 }
1102 }
1103 else
1104 {
1106 if (val)
1107 {
1109 if (verbosity != PQERRORS_TERSE && querytext != NULL)
1110 {
1111 /* emit position as a syntax cursor display */
1112 querypos = atoi(val);
1113 }
1114 else
1115 {
1116 /* emit position as text addition to primary message */
1117 /* translator: %s represents a digit string */
1118 appendPQExpBuffer(msg, libpq_gettext(" at character %s"),
1119 val);
1120 }
1121 }
1122 }
1123 appendPQExpBufferChar(msg, '\n');
1124 if (verbosity != PQERRORS_TERSE)
1125 {
1126 if (querytext && querypos > 0)
1127 reportErrorPosition(msg, querytext, querypos,
1128 res->client_encoding);
1130 if (val)
1131 appendPQExpBuffer(msg, libpq_gettext("DETAIL: %s\n"), val);
1133 if (val)
1134 appendPQExpBuffer(msg, libpq_gettext("HINT: %s\n"), val);
1136 if (val)
1137 appendPQExpBuffer(msg, libpq_gettext("QUERY: %s\n"), val);
1138 if (show_context == PQSHOW_CONTEXT_ALWAYS ||
1139 (show_context == PQSHOW_CONTEXT_ERRORS &&
1141 {
1143 if (val)
1144 appendPQExpBuffer(msg, libpq_gettext("CONTEXT: %s\n"),
1145 val);
1146 }
1147 }
1148 if (verbosity == PQERRORS_VERBOSE)
1149 {
1151 if (val)
1153 libpq_gettext("SCHEMA NAME: %s\n"), val);
1155 if (val)
1157 libpq_gettext("TABLE NAME: %s\n"), val);
1159 if (val)
1161 libpq_gettext("COLUMN NAME: %s\n"), val);
1163 if (val)
1165 libpq_gettext("DATATYPE NAME: %s\n"), val);
1167 if (val)
1169 libpq_gettext("CONSTRAINT NAME: %s\n"), val);
1170 }
1171 if (verbosity == PQERRORS_VERBOSE)
1172 {
1173 const char *valf;
1174 const char *vall;
1175
1179 if (val || valf || vall)
1180 {
1181 appendPQExpBufferStr(msg, libpq_gettext("LOCATION: "));
1182 if (val)
1183 appendPQExpBuffer(msg, libpq_gettext("%s, "), val);
1184 if (valf && vall) /* unlikely we'd have just one */
1185 appendPQExpBuffer(msg, libpq_gettext("%s:%s"),
1186 valf, vall);
1187 appendPQExpBufferChar(msg, '\n');
1188 }
1189 }
1190}
static void reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding)
#define PQresultErrorField
Definition: libpq-be-fe.h:249
@ PGRES_FATAL_ERROR
Definition: libpq-fe.h:136
@ PQSHOW_CONTEXT_ALWAYS
Definition: libpq-fe.h:166
@ PQSHOW_CONTEXT_ERRORS
Definition: libpq-fe.h:165
@ PQERRORS_VERBOSE
Definition: libpq-fe.h:158
@ PQERRORS_TERSE
Definition: libpq-fe.h:156
@ PQERRORS_SQLSTATE
Definition: libpq-fe.h:159
#define PG_DIAG_INTERNAL_QUERY
Definition: postgres_ext.h:63
#define PG_DIAG_SCHEMA_NAME
Definition: postgres_ext.h:65
#define PG_DIAG_CONSTRAINT_NAME
Definition: postgres_ext.h:69
#define PG_DIAG_DATATYPE_NAME
Definition: postgres_ext.h:68
#define PG_DIAG_SOURCE_LINE
Definition: postgres_ext.h:71
#define PG_DIAG_STATEMENT_POSITION
Definition: postgres_ext.h:61
#define PG_DIAG_SOURCE_FILE
Definition: postgres_ext.h:70
#define PG_DIAG_MESSAGE_HINT
Definition: postgres_ext.h:60
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
#define PG_DIAG_TABLE_NAME
Definition: postgres_ext.h:66
#define PG_DIAG_MESSAGE_PRIMARY
Definition: postgres_ext.h:58
#define PG_DIAG_COLUMN_NAME
Definition: postgres_ext.h:67
#define PG_DIAG_MESSAGE_DETAIL
Definition: postgres_ext.h:59
#define PG_DIAG_CONTEXT
Definition: postgres_ext.h:64
#define PG_DIAG_SEVERITY
Definition: postgres_ext.h:55
#define PG_DIAG_SOURCE_FUNCTION
Definition: postgres_ext.h:72
#define PG_DIAG_INTERNAL_POSITION
Definition: postgres_ext.h:62
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
char * errMsg
Definition: libpq-int.h:193
PGMessageField * errFields
Definition: libpq-int.h:194
ExecStatusType resultStatus
Definition: libpq-int.h:174
char * errQuery
Definition: libpq-int.h:195
int client_encoding
Definition: libpq-int.h:186

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), pg_result::client_encoding, pg_result::errFields, pg_result::errMsg, pg_result::errQuery, libpq_gettext, 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_FATAL_ERROR, PQERRORS_SQLSTATE, PQERRORS_TERSE, PQERRORS_VERBOSE, PQresultErrorField, PQSHOW_CONTEXT_ALWAYS, PQSHOW_CONTEXT_ERRORS, reportErrorPosition(), pg_result::resultStatus, and val.

Referenced by pqGetErrorNotice3(), and PQresultVerboseErrorMessage().

◆ pqBuildStartupPacket3()

char * pqBuildStartupPacket3 ( PGconn conn,
int *  packetlen,
const PQEnvironmentOption options 
)

Definition at line 2372 of file fe-protocol3.c.

2374{
2375 char *startpacket;
2376
2377 *packetlen = build_startup_packet(conn, NULL, options);
2378 startpacket = (char *) malloc(*packetlen);
2379 if (!startpacket)
2380 return NULL;
2381 *packetlen = build_startup_packet(conn, startpacket, options);
2382 return startpacket;
2383}
static int build_startup_packet(const PGconn *conn, char *packet, const PQEnvironmentOption *options)

References build_startup_packet(), conn, and malloc.

Referenced by PQconnectPoll().

◆ pqEndcopy3()

int pqEndcopy3 ( PGconn conn)

Definition at line 2049 of file fe-protocol3.c.

2050{
2051 PGresult *result;
2052
2056 {
2057 libpq_append_conn_error(conn, "no COPY in progress");
2058 return 1;
2059 }
2060
2061 /* Send the CopyDone message if needed */
2064 {
2065 if (pqPutMsgStart(PqMsg_CopyDone, conn) < 0 ||
2066 pqPutMsgEnd(conn) < 0)
2067 return 1;
2068
2069 /*
2070 * If we sent the COPY command in extended-query mode, we must issue a
2071 * Sync as well.
2072 */
2073 if (conn->cmd_queue_head &&
2075 {
2076 if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
2077 pqPutMsgEnd(conn) < 0)
2078 return 1;
2079 }
2080 }
2081
2082 /*
2083 * make sure no data is waiting to be sent, abort if we are non-blocking
2084 * and the flush fails
2085 */
2087 return 1;
2088
2089 /* Return to active duty */
2091
2092 /*
2093 * Non blocking connections may have to abort at this point. If everyone
2094 * played the game there should be no problem, but in error scenarios the
2095 * expected messages may not have arrived yet. (We are assuming that the
2096 * backend's packetizing will ensure that CommandComplete arrives along
2097 * with the CopyDone; are there corner cases where that doesn't happen?)
2098 */
2100 return 1;
2101
2102 /* Wait for the completion response */
2103 result = PQgetResult(conn);
2104
2105 /* Expecting a successful result */
2106 if (result && result->resultStatus == PGRES_COMMAND_OK)
2107 {
2108 PQclear(result);
2109 return 0;
2110 }
2111
2112 /*
2113 * Trouble. For backwards-compatibility reasons, we issue the error
2114 * message as if it were a notice (would be nice to get rid of this
2115 * silliness, but too many apps probably don't handle errors from
2116 * PQendcopy reasonably). Note that the app can still obtain the error
2117 * status from the PGconn object.
2118 */
2119 if (conn->errorMessage.len > 0)
2120 {
2121 /* We have to strip the trailing newline ... pain in neck... */
2122 char svLast = conn->errorMessage.data[conn->errorMessage.len - 1];
2123
2124 if (svLast == '\n')
2125 conn->errorMessage.data[conn->errorMessage.len - 1] = '\0';
2127 conn->errorMessage.data[conn->errorMessage.len - 1] = svLast;
2128 }
2129
2130 PQclear(result);
2131
2132 return 1;
2133}
void pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
Definition: fe-exec.c:938
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:2042
int pqFlush(PGconn *conn)
Definition: fe-misc.c:994
int pqPutMsgStart(char msg_type, PGconn *conn)
Definition: fe-misc.c:473
int pqPutMsgEnd(PGconn *conn)
Definition: fe-misc.c:532
#define PQgetResult
Definition: libpq-be-fe.h:246
@ PGASYNC_COPY_OUT
Definition: libpq-int.h:223
@ PGQUERY_SIMPLE
Definition: libpq-int.h:320
#define pqIsnonblocking(conn)
Definition: libpq-int.h:930
#define PqMsg_Sync
Definition: protocol.h:27
PGNoticeHooks noticeHooks
Definition: libpq-int.h:454

References pg_conn::asyncStatus, pg_conn::cmd_queue_head, conn, PQExpBufferData::data, pg_conn::errorMessage, PQExpBufferData::len, libpq_append_conn_error(), pg_conn::noticeHooks, PGASYNC_BUSY, PGASYNC_COPY_BOTH, PGASYNC_COPY_IN, PGASYNC_COPY_OUT, PGQUERY_SIMPLE, PGRES_COMMAND_OK, PQclear, pqFlush(), PQgetResult, pqInternalNotice(), PQisBusy(), pqIsnonblocking, PqMsg_CopyDone, PqMsg_Sync, pqPutMsgEnd(), pqPutMsgStart(), PGcmdQueueEntry::queryclass, and pg_result::resultStatus.

Referenced by PQendcopy().

◆ pqFunctionCall3()

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 2142 of file fe-protocol3.c.

2146{
2147 bool needInput = false;
2149 char id;
2150 int msgLength;
2151 int avail;
2152 int i;
2153
2154 /* already validated by PQfn */
2156
2157 /* PQfn already validated connection state */
2158
2160 pqPutInt(fnid, 4, conn) < 0 || /* function id */
2161 pqPutInt(1, 2, conn) < 0 || /* # of format codes */
2162 pqPutInt(1, 2, conn) < 0 || /* format code: BINARY */
2163 pqPutInt(nargs, 2, conn) < 0) /* # of args */
2164 {
2165 /* error message should be set up already */
2166 return NULL;
2167 }
2168
2169 for (i = 0; i < nargs; ++i)
2170 { /* len.int4 + contents */
2171 if (pqPutInt(args[i].len, 4, conn))
2172 return NULL;
2173 if (args[i].len == -1)
2174 continue; /* it's NULL */
2175
2176 if (args[i].isint)
2177 {
2178 if (pqPutInt(args[i].u.integer, args[i].len, conn))
2179 return NULL;
2180 }
2181 else
2182 {
2183 if (pqPutnchar(args[i].u.ptr, args[i].len, conn))
2184 return NULL;
2185 }
2186 }
2187
2188 if (pqPutInt(1, 2, conn) < 0) /* result format code: BINARY */
2189 return NULL;
2190
2191 if (pqPutMsgEnd(conn) < 0 ||
2192 pqFlush(conn))
2193 return NULL;
2194
2195 for (;;)
2196 {
2197 if (needInput)
2198 {
2199 /* Wait for some data to arrive (or for the channel to close) */
2200 if (pqWait(true, false, conn) ||
2201 pqReadData(conn) < 0)
2202 break;
2203 }
2204
2205 /*
2206 * Scan the message. If we run out of data, loop around to try again.
2207 */
2208 needInput = true;
2209
2211 if (pqGetc(&id, conn))
2212 continue;
2213 if (pqGetInt(&msgLength, 4, conn))
2214 continue;
2215
2216 /*
2217 * Try to validate message type/length here. A length less than 4 is
2218 * definitely broken. Large lengths should only be believed for a few
2219 * message types.
2220 */
2221 if (msgLength < 4)
2222 {
2223 handleSyncLoss(conn, id, msgLength);
2224 break;
2225 }
2226 if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id))
2227 {
2228 handleSyncLoss(conn, id, msgLength);
2229 break;
2230 }
2231
2232 /*
2233 * Can't process if message body isn't all here yet.
2234 */
2235 msgLength -= 4;
2236 avail = conn->inEnd - conn->inCursor;
2237 if (avail < msgLength)
2238 {
2239 /*
2240 * Before looping, enlarge the input buffer if needed to hold the
2241 * whole message. See notes in parseInput.
2242 */
2243 if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
2244 conn))
2245 {
2246 /*
2247 * Abandon the connection. There's not much else we can
2248 * safely do; we can't just ignore the message or we could
2249 * miss important changes to the connection state.
2250 * pqCheckInBufferSpace() already reported the error.
2251 */
2253 break;
2254 }
2255 continue;
2256 }
2257
2258 /*
2259 * We should see V or E response to the command, but might get N
2260 * and/or A notices first. We also need to swallow the final Z before
2261 * returning.
2262 */
2263 switch (id)
2264 {
2266 if (pqGetInt(actual_result_len, 4, conn))
2267 continue;
2268 if (*actual_result_len != -1)
2269 {
2270 if (result_is_int)
2271 {
2272 if (pqGetInt(result_buf, *actual_result_len, conn))
2273 continue;
2274 }
2275 else
2276 {
2277 if (pqGetnchar(result_buf,
2278 *actual_result_len,
2279 conn))
2280 continue;
2281 }
2282 }
2283 /* correctly finished function result message */
2284 status = PGRES_COMMAND_OK;
2285 break;
2287 if (pqGetErrorNotice3(conn, true))
2288 continue;
2289 status = PGRES_FATAL_ERROR;
2290 break;
2292 /* handle notify and go back to processing return values */
2293 if (getNotify(conn))
2294 continue;
2295 break;
2297 /* handle notice and go back to processing return values */
2298 if (pqGetErrorNotice3(conn, false))
2299 continue;
2300 break;
2303 continue;
2304
2305 /* consume the message */
2306 pqParseDone(conn, conn->inStart + 5 + msgLength);
2307
2308 /*
2309 * If we already have a result object (probably an error), use
2310 * that. Otherwise, if we saw a function result message,
2311 * report COMMAND_OK. Otherwise, the backend violated the
2312 * protocol, so complain.
2313 */
2315 {
2316 if (status == PGRES_COMMAND_OK)
2317 {
2318 conn->result = PQmakeEmptyPGresult(conn, status);
2319 if (!conn->result)
2320 {
2321 libpq_append_conn_error(conn, "out of memory");
2323 }
2324 }
2325 else
2326 {
2327 libpq_append_conn_error(conn, "protocol error: no function result");
2329 }
2330 }
2331 /* and we're out */
2332 return pqPrepareAsyncResult(conn);
2335 continue;
2336 break;
2337 default:
2338 /* The backend violates the protocol. */
2339 libpq_append_conn_error(conn, "protocol error: id=0x%x", id);
2341
2342 /*
2343 * We can't call parsing done due to the protocol violation
2344 * (so message tracing wouldn't work), but trust the specified
2345 * message length as what to skip.
2346 */
2347 conn->inStart += 5 + msgLength;
2348 return pqPrepareAsyncResult(conn);
2349 }
2350
2351 /* Completed parsing this message, keep going */
2352 pqParseDone(conn, conn->inStart + 5 + msgLength);
2353 needInput = false;
2354 }
2355
2356 /*
2357 * We fall out of the loop only upon failing to read data.
2358 * conn->errorMessage has been set by pqWait or pqReadData. We want to
2359 * append it to any already-received error message.
2360 */
2362 return pqPrepareAsyncResult(conn);
2363}
PGresult * pqPrepareAsyncResult(PGconn *conn)
Definition: fe-exec.c:851
int pqReadData(PGconn *conn)
Definition: fe-misc.c:606
int pqPutInt(int value, size_t bytes, PGconn *conn)
Definition: fe-misc.c:253
int pqWait(int forRead, int forWrite, PGconn *conn)
Definition: fe-misc.c:1019
int pqPutnchar(const void *s, size_t len, PGconn *conn)
Definition: fe-misc.c:202
#define VALID_LONG_MESSAGE_TYPE(id)
Definition: fe-protocol3.c:36
static int getReadyForQuery(PGconn *conn)
Assert(PointerIsAligned(start, uint64))
ExecStatusType
Definition: libpq-fe.h:123
@ PQ_PIPELINE_OFF
Definition: libpq-fe.h:187
#define pgHavePendingResult(conn)
Definition: libpq-int.h:923
const void size_t len
#define PqMsg_FunctionCall
Definition: protocol.h:23
#define PqMsg_ReadyForQuery
Definition: protocol.h:55
PGpipelineStatus pipelineStatus
Definition: libpq-int.h:469

References generate_unaccent_rules::args, Assert(), conn, getNotify(), getParameterStatus(), getReadyForQuery(), handleFatalError(), handleSyncLoss(), i, pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, len, libpq_append_conn_error(), pgHavePendingResult, PGRES_COMMAND_OK, PGRES_FATAL_ERROR, pg_conn::pipelineStatus, PQ_PIPELINE_OFF, pqCheckInBufferSpace(), pqFlush(), pqGetc(), pqGetErrorNotice3(), pqGetInt(), pqGetnchar(), PQmakeEmptyPGresult(), PqMsg_ErrorResponse, PqMsg_FunctionCall, PqMsg_FunctionCallResponse, PqMsg_NoticeResponse, PqMsg_NotificationResponse, PqMsg_ParameterStatus, PqMsg_ReadyForQuery, pqParseDone(), pqPrepareAsyncResult(), pqPutInt(), pqPutMsgEnd(), pqPutMsgStart(), pqPutnchar(), pqReadData(), pqSaveErrorResult(), pqWait(), pg_conn::result, and VALID_LONG_MESSAGE_TYPE.

Referenced by PQfn().

◆ pqGetCopyData3()

int pqGetCopyData3 ( PGconn conn,
char **  buffer,
int  async 
)

Definition at line 1884 of file fe-protocol3.c.

1885{
1886 int msgLength;
1887
1888 for (;;)
1889 {
1890 /*
1891 * Collect the next input message. To make life simpler for async
1892 * callers, we keep returning 0 until the next message is fully
1893 * available, even if it is not Copy Data.
1894 */
1895 msgLength = getCopyDataMessage(conn);
1896 if (msgLength < 0)
1897 return msgLength; /* end-of-copy or error */
1898 if (msgLength == 0)
1899 {
1900 /* Don't block if async read requested */
1901 if (async)
1902 return 0;
1903 /* Need to load more data */
1904 if (pqWait(true, false, conn) ||
1905 pqReadData(conn) < 0)
1906 return -2;
1907 continue;
1908 }
1909
1910 /*
1911 * Drop zero-length messages (shouldn't happen anyway). Otherwise
1912 * pass the data back to the caller.
1913 */
1914 msgLength -= 4;
1915 if (msgLength > 0)
1916 {
1917 *buffer = (char *) malloc(msgLength + 1);
1918 if (*buffer == NULL)
1919 {
1920 libpq_append_conn_error(conn, "out of memory");
1921 return -2;
1922 }
1923 memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength);
1924 (*buffer)[msgLength] = '\0'; /* Add terminating null */
1925
1926 /* Mark message consumed */
1927 pqParseDone(conn, conn->inCursor + msgLength);
1928
1929 return msgLength;
1930 }
1931
1932 /* Empty, so drop it and loop around for another */
1934 }
1935}
static int getCopyDataMessage(PGconn *conn)

References conn, getCopyDataMessage(), pg_conn::inBuffer, pg_conn::inCursor, libpq_append_conn_error(), malloc, pqParseDone(), pqReadData(), and pqWait().

Referenced by PQgetCopyData().

◆ pqGetErrorNotice3()

int pqGetErrorNotice3 ( PGconn conn,
bool  isError 
)

Definition at line 896 of file fe-protocol3.c.

897{
898 PGresult *res = NULL;
899 bool have_position = false;
900 PQExpBufferData workBuf;
901 char id;
902
903 /* If in pipeline mode, set error indicator for it */
904 if (isError && conn->pipelineStatus != PQ_PIPELINE_OFF)
906
907 /*
908 * If this is an error message, pre-emptively clear any incomplete query
909 * result we may have. We'd just throw it away below anyway, and
910 * releasing it before collecting the error might avoid out-of-memory.
911 */
912 if (isError)
914
915 /*
916 * Since the fields might be pretty long, we create a temporary
917 * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended
918 * for stuff that is expected to be short. We shouldn't use
919 * conn->errorMessage either, since this might be only a notice.
920 */
921 initPQExpBuffer(&workBuf);
922
923 /*
924 * Make a PGresult to hold the accumulated fields. We temporarily lie
925 * about the result status, so that PQmakeEmptyPGresult doesn't uselessly
926 * copy conn->errorMessage.
927 *
928 * NB: This allocation can fail, if you run out of memory. The rest of the
929 * function handles that gracefully, and we still try to set the error
930 * message as the connection's error message.
931 */
933 if (res)
935
936 /*
937 * Read the fields and save into res.
938 *
939 * While at it, save the SQLSTATE in conn->last_sqlstate, and note whether
940 * we saw a PG_DIAG_STATEMENT_POSITION field.
941 */
942 for (;;)
943 {
944 if (pqGetc(&id, conn))
945 goto fail;
946 if (id == '\0')
947 break; /* terminator found */
948 if (pqGets(&workBuf, conn))
949 goto fail;
950 pqSaveMessageField(res, id, workBuf.data);
951 if (id == PG_DIAG_SQLSTATE)
952 strlcpy(conn->last_sqlstate, workBuf.data,
953 sizeof(conn->last_sqlstate));
954 else if (id == PG_DIAG_STATEMENT_POSITION)
955 have_position = true;
956 }
957
958 /*
959 * Save the active query text, if any, into res as well; but only if we
960 * might need it for an error cursor display, which is only true if there
961 * is a PG_DIAG_STATEMENT_POSITION field.
962 */
963 if (have_position && res && conn->cmd_queue_head && conn->cmd_queue_head->query)
965
966 /*
967 * Now build the "overall" error message for PQresultErrorMessage.
968 */
969 resetPQExpBuffer(&workBuf);
971
972 /*
973 * Either save error as current async result, or just emit the notice.
974 */
975 if (isError)
976 {
977 pqClearAsyncResult(conn); /* redundant, but be safe */
978 if (res)
979 {
980 pqSetResultError(res, &workBuf, 0);
981 conn->result = res;
982 }
983 else
984 {
985 /* Fall back to using the internal-error processing paths */
986 conn->error_result = true;
987 }
988
989 if (PQExpBufferDataBroken(workBuf))
990 libpq_append_conn_error(conn, "out of memory");
991 else
993 }
994 else
995 {
996 /* if we couldn't allocate the result set, just discard the NOTICE */
997 if (res)
998 {
999 /*
1000 * We can cheat a little here and not copy the message. But if we
1001 * were unlucky enough to run out of memory while filling workBuf,
1002 * insert "out of memory", as in pqSetResultError.
1003 */
1004 if (PQExpBufferDataBroken(workBuf))
1005 res->errMsg = libpq_gettext("out of memory\n");
1006 else
1007 res->errMsg = workBuf.data;
1008 if (res->noticeHooks.noticeRec != NULL)
1010 PQclear(res);
1011 }
1012 }
1013
1014 termPQExpBuffer(&workBuf);
1015 return 0;
1016
1017fail:
1018 PQclear(res);
1019 termPQExpBuffer(&workBuf);
1020 return EOF;
1021}
void pqSaveMessageField(PGresult *res, char code, const char *value)
Definition: fe-exec.c:1060
void pqSetResultError(PGresult *res, PQExpBuffer errorMessage, int offset)
Definition: fe-exec.c:692
void pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res, PGVerbosity verbosity, PGContextVisibility show_context)
@ PGRES_EMPTY_QUERY
Definition: libpq-fe.h:124
@ PGRES_NONFATAL_ERROR
Definition: libpq-fe.h:135
@ PQ_PIPELINE_ABORTED
Definition: libpq-fe.h:189
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
PQnoticeReceiver noticeRec
Definition: libpq-int.h:149
void * noticeRecArg
Definition: libpq-int.h:150
PGVerbosity verbosity
Definition: libpq-int.h:560
bool error_result
Definition: libpq-int.h:598
char last_sqlstate[6]
Definition: libpq-int.h:465
PGContextVisibility show_context
Definition: libpq-int.h:561
PGNoticeHooks noticeHooks
Definition: libpq-int.h:183

References appendPQExpBufferStr(), pg_conn::cmd_queue_head, conn, PQExpBufferData::data, pg_result::errMsg, pg_conn::error_result, pg_conn::errorMessage, pg_result::errQuery, initPQExpBuffer(), pg_conn::last_sqlstate, libpq_append_conn_error(), libpq_gettext, pg_result::noticeHooks, PGNoticeHooks::noticeRec, PGNoticeHooks::noticeRecArg, PG_DIAG_SQLSTATE, PG_DIAG_STATEMENT_POSITION, PGRES_EMPTY_QUERY, PGRES_FATAL_ERROR, PGRES_NONFATAL_ERROR, pg_conn::pipelineStatus, PQ_PIPELINE_ABORTED, PQ_PIPELINE_OFF, pqBuildErrorMessage3(), PQclear, pqClearAsyncResult(), PQExpBufferDataBroken, pqGetc(), pqGets(), PQmakeEmptyPGresult(), pqResultStrdup(), pqSaveMessageField(), pqSetResultError(), PGcmdQueueEntry::query, resetPQExpBuffer(), pg_conn::result, pg_result::resultStatus, pg_conn::show_context, strlcpy(), termPQExpBuffer(), and pg_conn::verbosity.

Referenced by getCopyDataMessage(), PQconnectPoll(), pqFunctionCall3(), and pqParseInput3().

◆ pqGetline3()

int pqGetline3 ( PGconn conn,
char *  s,
int  maxlen 
)

Definition at line 1943 of file fe-protocol3.c.

1944{
1945 int status;
1946
1947 if (conn->sock == PGINVALID_SOCKET ||
1951 {
1952 libpq_append_conn_error(conn, "PQgetline: not doing text COPY OUT");
1953 *s = '\0';
1954 return EOF;
1955 }
1956
1957 while ((status = PQgetlineAsync(conn, s, maxlen - 1)) == 0)
1958 {
1959 /* need to load more data */
1960 if (pqWait(true, false, conn) ||
1961 pqReadData(conn) < 0)
1962 {
1963 *s = '\0';
1964 return EOF;
1965 }
1966 }
1967
1968 if (status < 0)
1969 {
1970 /* End of copy detected; gin up old-style terminator */
1971 strcpy(s, "\\.");
1972 return 0;
1973 }
1974
1975 /* Add null terminator, and strip trailing \n if present */
1976 if (s[status - 1] == '\n')
1977 {
1978 s[status - 1] = '\0';
1979 return 0;
1980 }
1981 else
1982 {
1983 s[status] = '\0';
1984 return 1;
1985 }
1986}
int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize)
Definition: fe-exec.c:2912
#define PGINVALID_SOCKET
Definition: port.h:31
pgsocket sock
Definition: libpq-int.h:499

References pg_conn::asyncStatus, conn, pg_conn::copy_is_binary, libpq_append_conn_error(), PGASYNC_COPY_BOTH, PGASYNC_COPY_OUT, PGINVALID_SOCKET, PQgetlineAsync(), pqReadData(), pqWait(), and pg_conn::sock.

Referenced by PQgetline().

◆ pqGetlineAsync3()

int pqGetlineAsync3 ( PGconn conn,
char *  buffer,
int  bufsize 
)

Definition at line 1994 of file fe-protocol3.c.

1995{
1996 int msgLength;
1997 int avail;
1998
2001 return -1; /* we are not doing a copy... */
2002
2003 /*
2004 * Recognize the next input message. To make life simpler for async
2005 * callers, we keep returning 0 until the next message is fully available
2006 * even if it is not Copy Data. This should keep PQendcopy from blocking.
2007 * (Note: unlike pqGetCopyData3, we do not change asyncStatus here.)
2008 */
2009 msgLength = getCopyDataMessage(conn);
2010 if (msgLength < 0)
2011 return -1; /* end-of-copy or error */
2012 if (msgLength == 0)
2013 return 0; /* no data yet */
2014
2015 /*
2016 * Move data from libpq's buffer to the caller's. In the case where a
2017 * prior call found the caller's buffer too small, we use
2018 * conn->copy_already_done to remember how much of the row was already
2019 * returned to the caller.
2020 */
2022 avail = msgLength - 4 - conn->copy_already_done;
2023 if (avail <= bufsize)
2024 {
2025 /* Able to consume the whole message */
2026 memcpy(buffer, &conn->inBuffer[conn->inCursor], avail);
2027 /* Mark message consumed */
2028 conn->inStart = conn->inCursor + avail;
2029 /* Reset state for next time */
2031 return avail;
2032 }
2033 else
2034 {
2035 /* We must return a partial message */
2036 memcpy(buffer, &conn->inBuffer[conn->inCursor], bufsize);
2037 /* The message is NOT consumed from libpq's buffer */
2039 return bufsize;
2040 }
2041}
#define bufsize
Definition: indent_globs.h:36
int copy_already_done
Definition: libpq-int.h:475

References pg_conn::asyncStatus, bufsize, conn, 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().

◆ pqGetNegotiateProtocolVersion3()

int pqGetNegotiateProtocolVersion3 ( PGconn conn)

Definition at line 1428 of file fe-protocol3.c.

1429{
1430 int their_version;
1431 int num;
1432
1433 if (pqGetInt(&their_version, 4, conn) != 0)
1434 goto eof;
1435
1436 if (pqGetInt(&num, 4, conn) != 0)
1437 goto eof;
1438
1439 /* Check the protocol version */
1440 if (their_version > conn->pversion)
1441 {
1442 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to a higher-numbered version");
1443 goto failure;
1444 }
1445
1446 if (their_version < PG_PROTOCOL(3, 0))
1447 {
1448 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to pre-3.0 protocol version");
1449 goto failure;
1450 }
1451
1452 /* 3.1 never existed, we went straight from 3.0 to 3.2 */
1453 if (their_version == PG_PROTOCOL(3, 1))
1454 {
1455 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to non-existent 3.1 protocol version");
1456 goto failure;
1457 }
1458
1459 if (num < 0)
1460 {
1461 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported negative number of unsupported parameters");
1462 goto failure;
1463 }
1464
1465 if (their_version == conn->pversion && num == 0)
1466 {
1467 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server negotiated but asks for no changes");
1468 goto failure;
1469 }
1470
1471 if (their_version < conn->min_pversion)
1472 {
1473 libpq_append_conn_error(conn, "server only supports protocol version %d.%d, but \"%s\" was set to %d.%d",
1474 PG_PROTOCOL_MAJOR(their_version),
1475 PG_PROTOCOL_MINOR(their_version),
1476 "min_protocol_version",
1479
1480 goto failure;
1481 }
1482
1483 /* the version is acceptable */
1484 conn->pversion = their_version;
1485
1486 /*
1487 * We don't currently request any protocol extensions, so we don't expect
1488 * the server to reply with any either.
1489 */
1490 for (int i = 0; i < num; i++)
1491 {
1492 if (pqGets(&conn->workBuffer, conn))
1493 {
1494 goto eof;
1495 }
1496 if (strncmp(conn->workBuffer.data, "_pq_.", 5) != 0)
1497 {
1498 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported unsupported parameter name without a \"%s\" prefix (\"%s\")", "_pq_.", conn->workBuffer.data);
1499 goto failure;
1500 }
1501 libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported an unsupported parameter that was not requested (\"%s\")", conn->workBuffer.data);
1502 goto failure;
1503 }
1504
1505 return 0;
1506
1507eof:
1508 libpq_append_conn_error(conn, "received invalid protocol negotiation message: message too short");
1509failure:
1512 return 1;
1513}
#define PG_PROTOCOL_MAJOR(v)
Definition: pqcomm.h:87
#define PG_PROTOCOL_MINOR(v)
Definition: pqcomm.h:88
ProtocolVersion min_pversion
Definition: libpq-int.h:548

References pg_conn::asyncStatus, conn, PQExpBufferData::data, i, libpq_append_conn_error(), pg_conn::min_pversion, PG_PROTOCOL, PG_PROTOCOL_MAJOR, PG_PROTOCOL_MINOR, PGASYNC_READY, pqGetInt(), pqGets(), pqSaveErrorResult(), pg_conn::pversion, and pg_conn::workBuffer.

Referenced by PQconnectPoll().

◆ pqParseInput3()

void pqParseInput3 ( PGconn conn)

Definition at line 68 of file fe-protocol3.c.

69{
70 char id;
71 int msgLength;
72 int avail;
73
74 /*
75 * Loop to parse successive complete messages available in the buffer.
76 */
77 for (;;)
78 {
79 /*
80 * Try to read a message. First get the type code and length. Return
81 * if not enough data.
82 */
84 if (pqGetc(&id, conn))
85 return;
86 if (pqGetInt(&msgLength, 4, conn))
87 return;
88
89 /*
90 * Try to validate message type/length here. A length less than 4 is
91 * definitely broken. Large lengths should only be believed for a few
92 * message types.
93 */
94 if (msgLength < 4)
95 {
96 handleSyncLoss(conn, id, msgLength);
97 return;
98 }
99 if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id))
100 {
101 handleSyncLoss(conn, id, msgLength);
102 return;
103 }
104
105 /*
106 * Can't process if message body isn't all here yet.
107 */
108 msgLength -= 4;
109 avail = conn->inEnd - conn->inCursor;
110 if (avail < msgLength)
111 {
112 /*
113 * Before returning, enlarge the input buffer if needed to hold
114 * the whole message. This is better than leaving it to
115 * pqReadData because we can avoid multiple cycles of realloc()
116 * when the message is large; also, we can implement a reasonable
117 * recovery strategy if we are unable to make the buffer big
118 * enough.
119 */
120 if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
121 conn))
122 {
123 /*
124 * Abandon the connection. There's not much else we can
125 * safely do; we can't just ignore the message or we could
126 * miss important changes to the connection state.
127 * pqCheckInBufferSpace() already reported the error.
128 */
130 }
131 return;
132 }
133
134 /*
135 * NOTIFY and NOTICE messages can happen in any state; always process
136 * them right away.
137 *
138 * Most other messages should only be processed while in BUSY state.
139 * (In particular, in READY state we hold off further parsing until
140 * the application collects the current PGresult.)
141 *
142 * However, if the state is IDLE then we got trouble; we need to deal
143 * with the unexpected message somehow.
144 *
145 * ParameterStatus ('S') messages are a special case: in IDLE state we
146 * must process 'em (this case could happen if a new value was adopted
147 * from config file due to SIGHUP), but otherwise we hold off until
148 * BUSY state.
149 */
151 {
152 if (getNotify(conn))
153 return;
154 }
155 else if (id == PqMsg_NoticeResponse)
156 {
157 if (pqGetErrorNotice3(conn, false))
158 return;
159 }
160 else if (conn->asyncStatus != PGASYNC_BUSY)
161 {
162 /* If not IDLE state, just wait ... */
164 return;
165
166 /*
167 * Unexpected message in IDLE state; need to recover somehow.
168 * ERROR messages are handled using the notice processor;
169 * ParameterStatus is handled normally; anything else is just
170 * dropped on the floor after displaying a suitable warning
171 * notice. (An ERROR is very possibly the backend telling us why
172 * it is about to close the connection, so we don't want to just
173 * discard it...)
174 */
175 if (id == PqMsg_ErrorResponse)
176 {
177 if (pqGetErrorNotice3(conn, false /* treat as notice */ ))
178 return;
179 }
180 else if (id == PqMsg_ParameterStatus)
181 {
183 return;
184 }
185 else
186 {
187 /* Any other case is unexpected and we summarily skip it */
189 "message type 0x%02x arrived from server while idle",
190 id);
191 /* Discard the unexpected message */
192 conn->inCursor += msgLength;
193 }
194 }
195 else
196 {
197 /*
198 * In BUSY state, we can process everything.
199 */
200 switch (id)
201 {
203 if (pqGets(&conn->workBuffer, conn))
204 return;
206 {
209 if (!conn->result)
210 {
211 libpq_append_conn_error(conn, "out of memory");
213 }
214 }
215 if (conn->result)
219 break;
221 if (pqGetErrorNotice3(conn, true))
222 return;
224 break;
227 return;
229 {
232 if (!conn->result)
233 {
234 libpq_append_conn_error(conn, "out of memory");
236 }
237 else
238 {
241 }
242 }
243 else
244 {
245 /* Advance the command queue and set us idle */
246 pqCommandQueueAdvance(conn, true, false);
248 }
249 break;
252 {
255 if (!conn->result)
256 {
257 libpq_append_conn_error(conn, "out of memory");
259 }
260 }
262 break;
264 /* If we're doing PQprepare, we're done; else ignore */
265 if (conn->cmd_queue_head &&
267 {
269 {
272 if (!conn->result)
273 {
274 libpq_append_conn_error(conn, "out of memory");
276 }
277 }
279 }
280 break;
282 /* Nothing to do for this message type */
283 break;
285 /* If we're doing PQsendClose, we're done; else ignore */
286 if (conn->cmd_queue_head &&
288 {
290 {
293 if (!conn->result)
294 {
295 libpq_append_conn_error(conn, "out of memory");
297 }
298 }
300 }
301 break;
304 return;
305 break;
307
308 /*
309 * This is expected only during backend startup, but it's
310 * just as easy to handle it as part of the main loop.
311 * Save the data and continue processing.
312 */
313 if (getBackendKeyData(conn, msgLength))
314 return;
315 break;
317 if (conn->error_result ||
318 (conn->result != NULL &&
320 {
321 /*
322 * We've already choked for some reason. Just discard
323 * the data till we get to the end of the query.
324 */
325 conn->inCursor += msgLength;
326 }
327 else if (conn->result == NULL ||
330 {
331 /* First 'T' in a query sequence */
332 if (getRowDescriptions(conn, msgLength))
333 return;
334 }
335 else
336 {
337 /*
338 * A new 'T' message is treated as the start of
339 * another PGresult. (It is not clear that this is
340 * really possible with the current backend.) We stop
341 * parsing until the application accepts the current
342 * result.
343 */
345 return;
346 }
347 break;
348 case PqMsg_NoData:
349
350 /*
351 * NoData indicates that we will not be seeing a
352 * RowDescription message because the statement or portal
353 * inquired about doesn't return rows.
354 *
355 * If we're doing a Describe, we have to pass something
356 * back to the client, so set up a COMMAND_OK result,
357 * instead of PGRES_TUPLES_OK. Otherwise we can just
358 * ignore this message.
359 */
360 if (conn->cmd_queue_head &&
362 {
364 {
367 if (!conn->result)
368 {
369 libpq_append_conn_error(conn, "out of memory");
371 }
372 }
374 }
375 break;
377 if (getParamDescriptions(conn, msgLength))
378 return;
379 break;
380 case PqMsg_DataRow:
381 if (conn->result != NULL &&
384 {
385 /* Read another tuple of a normal query response */
386 if (getAnotherTuple(conn, msgLength))
387 return;
388 }
389 else if (conn->error_result ||
390 (conn->result != NULL &&
392 {
393 /*
394 * We've already choked for some reason. Just discard
395 * tuples till we get to the end of the query.
396 */
397 conn->inCursor += msgLength;
398 }
399 else
400 {
401 /* Set up to report error at end of query */
402 libpq_append_conn_error(conn, "server sent data (\"D\" message) without prior row description (\"T\" message)");
404 /* Discard the unexpected message */
405 conn->inCursor += msgLength;
406 }
407 break;
410 return;
412 break;
415 return;
418 break;
421 return;
424 break;
425 case PqMsg_CopyData:
426
427 /*
428 * If we see Copy Data, just silently drop it. This would
429 * only occur if application exits COPY OUT mode too
430 * early.
431 */
432 conn->inCursor += msgLength;
433 break;
434 case PqMsg_CopyDone:
435
436 /*
437 * If we see Copy Done, just silently drop it. This is
438 * the normal case during PQendcopy. We will keep
439 * swallowing data, expecting to see command-complete for
440 * the COPY command.
441 */
442 break;
443 default:
444 libpq_append_conn_error(conn, "unexpected response from server; first received character was \"%c\"", id);
445 /* build an error result holding the error message */
447 /* not sure if we will see more, so go to ready state */
449 /* Discard the unexpected message */
450 conn->inCursor += msgLength;
451 break;
452 } /* switch on protocol character */
453 }
454 /* Successfully consumed this message */
455 if (conn->inCursor == conn->inStart + 5 + msgLength)
456 {
457 /* Normal case: parsing agrees with specified length */
459 }
460 else if (conn->error_result && conn->status == CONNECTION_BAD)
461 {
462 /* The connection was abandoned and we already reported it */
463 return;
464 }
465 else
466 {
467 /* Trouble --- report it */
468 libpq_append_conn_error(conn, "message contents do not agree with length in message type \"%c\"", id);
469 /* build an error result holding the error message */
472 /* trust the specified message length as what to skip */
473 conn->inStart += 5 + msgLength;
474 }
475 }
476}
void pqCommandQueueAdvance(PGconn *conn, bool isReadyForQuery, bool gotSync)
Definition: fe-exec.c:3153
static int getAnotherTuple(PGconn *conn, int msgLength)
Definition: fe-protocol3.c:775
static int getRowDescriptions(PGconn *conn, int msgLength)
Definition: fe-protocol3.c:516
static int getCopyStart(PGconn *conn, ExecStatusType copytype)
static int getBackendKeyData(PGconn *conn, int msgLength)
static int getParamDescriptions(PGconn *conn, int msgLength)
Definition: fe-protocol3.c:687
@ PGRES_COPY_IN
Definition: libpq-fe.h:132
@ PGRES_COPY_BOTH
Definition: libpq-fe.h:137
@ PGRES_TUPLES_CHUNK
Definition: libpq-fe.h:142
@ PGRES_COPY_OUT
Definition: libpq-fe.h:131
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:139
@ PQ_PIPELINE_ON
Definition: libpq-fe.h:188
@ PGASYNC_IDLE
Definition: libpq-int.h:215
@ PGQUERY_CLOSE
Definition: libpq-int.h:325
@ PGQUERY_PREPARE
Definition: libpq-int.h:322
#define CMDSTATUS_LEN
Definition: libpq-int.h:83
#define PqMsg_CloseComplete
Definition: protocol.h:40
#define PqMsg_BindComplete
Definition: protocol.h:39
#define PqMsg_ParameterDescription
Definition: protocol.h:58
#define PqMsg_CopyInResponse
Definition: protocol.h:45
#define PqMsg_EmptyQueryResponse
Definition: protocol.h:47
#define PqMsg_CopyBothResponse
Definition: protocol.h:54
#define PqMsg_NoData
Definition: protocol.h:56
#define PqMsg_BackendKeyData
Definition: protocol.h:48
#define PqMsg_CommandComplete
Definition: protocol.h:42
#define PqMsg_CopyOutResponse
Definition: protocol.h:46
#define PqMsg_ParseComplete
Definition: protocol.h:38
char cmdStatus[CMDSTATUS_LEN]
Definition: libpq-int.h:175

References pg_conn::asyncStatus, pg_conn::cmd_queue_head, pg_result::cmdStatus, CMDSTATUS_LEN, conn, CONNECTION_BAD, pg_conn::copy_already_done, PQExpBufferData::data, pg_conn::error_result, getAnotherTuple(), getBackendKeyData(), getCopyStart(), getNotify(), getParamDescriptions(), getParameterStatus(), getReadyForQuery(), getRowDescriptions(), handleFatalError(), handleSyncLoss(), pg_conn::inCursor, pg_conn::inEnd, pg_conn::inStart, libpq_append_conn_error(), pg_conn::noticeHooks, PGASYNC_BUSY, PGASYNC_COPY_BOTH, PGASYNC_COPY_IN, PGASYNC_COPY_OUT, PGASYNC_IDLE, PGASYNC_READY, pgHavePendingResult, PGQUERY_CLOSE, PGQUERY_DESCRIBE, PGQUERY_PREPARE, PGRES_COMMAND_OK, PGRES_COPY_BOTH, PGRES_COPY_IN, PGRES_COPY_OUT, PGRES_EMPTY_QUERY, PGRES_FATAL_ERROR, PGRES_PIPELINE_SYNC, PGRES_TUPLES_CHUNK, PGRES_TUPLES_OK, pg_conn::pipelineStatus, PQ_PIPELINE_OFF, PQ_PIPELINE_ON, pqCheckInBufferSpace(), pqCommandQueueAdvance(), pqGetc(), pqGetErrorNotice3(), pqGetInt(), pqGets(), pqInternalNotice(), PQmakeEmptyPGresult(), PqMsg_BackendKeyData, PqMsg_BindComplete, PqMsg_CloseComplete, PqMsg_CommandComplete, PqMsg_CopyBothResponse, PqMsg_CopyData, PqMsg_CopyDone, PqMsg_CopyInResponse, PqMsg_CopyOutResponse, PqMsg_DataRow, PqMsg_EmptyQueryResponse, PqMsg_ErrorResponse, PqMsg_NoData, PqMsg_NoticeResponse, PqMsg_NotificationResponse, PqMsg_ParameterDescription, PqMsg_ParameterStatus, PqMsg_ParseComplete, PqMsg_ReadyForQuery, PqMsg_RowDescription, pqParseDone(), pqSaveErrorResult(), PGcmdQueueEntry::queryclass, pg_conn::result, pg_result::resultStatus, pg_conn::status, strlcpy(), VALID_LONG_MESSAGE_TYPE, and pg_conn::workBuffer.

Referenced by parseInput().

◆ reportErrorPosition()

static void reportErrorPosition ( PQExpBuffer  msg,
const char *  query,
int  loc,
int  encoding 
)
static

Definition at line 1199 of file fe-protocol3.c.

1200{
1201#define DISPLAY_SIZE 60 /* screen width limit, in screen cols */
1202#define MIN_RIGHT_CUT 10 /* try to keep this far away from EOL */
1203
1204 char *wquery;
1205 int slen,
1206 cno,
1207 i,
1208 *qidx,
1209 *scridx,
1210 qoffset,
1211 scroffset,
1212 ibeg,
1213 iend,
1214 loc_line;
1215 bool mb_encoding,
1216 beg_trunc,
1217 end_trunc;
1218
1219 /* Convert loc from 1-based to 0-based; no-op if out of range */
1220 loc--;
1221 if (loc < 0)
1222 return;
1223
1224 /* Need a writable copy of the query */
1225 wquery = strdup(query);
1226 if (wquery == NULL)
1227 return; /* fail silently if out of memory */
1228
1229 /*
1230 * Each character might occupy multiple physical bytes in the string, and
1231 * in some Far Eastern character sets it might take more than one screen
1232 * column as well. We compute the starting byte offset and starting
1233 * screen column of each logical character, and store these in qidx[] and
1234 * scridx[] respectively.
1235 */
1236
1237 /* we need a safe allocation size... */
1238 slen = strlen(wquery) + 1;
1239
1240 qidx = (int *) malloc(slen * sizeof(int));
1241 if (qidx == NULL)
1242 {
1243 free(wquery);
1244 return;
1245 }
1246 scridx = (int *) malloc(slen * sizeof(int));
1247 if (scridx == NULL)
1248 {
1249 free(qidx);
1250 free(wquery);
1251 return;
1252 }
1253
1254 /* We can optimize a bit if it's a single-byte encoding */
1255 mb_encoding = (pg_encoding_max_length(encoding) != 1);
1256
1257 /*
1258 * Within the scanning loop, cno is the current character's logical
1259 * number, qoffset is its offset in wquery, and scroffset is its starting
1260 * logical screen column (all indexed from 0). "loc" is the logical
1261 * character number of the error location. We scan to determine loc_line
1262 * (the 1-based line number containing loc) and ibeg/iend (first character
1263 * number and last+1 character number of the line containing loc). Note
1264 * that qidx[] and scridx[] are filled only as far as iend.
1265 */
1266 qoffset = 0;
1267 scroffset = 0;
1268 loc_line = 1;
1269 ibeg = 0;
1270 iend = -1; /* -1 means not set yet */
1271
1272 for (cno = 0; wquery[qoffset] != '\0'; cno++)
1273 {
1274 char ch = wquery[qoffset];
1275
1276 qidx[cno] = qoffset;
1277 scridx[cno] = scroffset;
1278
1279 /*
1280 * Replace tabs with spaces in the writable copy. (Later we might
1281 * want to think about coping with their variable screen width, but
1282 * not today.)
1283 */
1284 if (ch == '\t')
1285 wquery[qoffset] = ' ';
1286
1287 /*
1288 * If end-of-line, count lines and mark positions. Each \r or \n
1289 * counts as a line except when \r \n appear together.
1290 */
1291 else if (ch == '\r' || ch == '\n')
1292 {
1293 if (cno < loc)
1294 {
1295 if (ch == '\r' ||
1296 cno == 0 ||
1297 wquery[qidx[cno - 1]] != '\r')
1298 loc_line++;
1299 /* extract beginning = last line start before loc. */
1300 ibeg = cno + 1;
1301 }
1302 else
1303 {
1304 /* set extract end. */
1305 iend = cno;
1306 /* done scanning. */
1307 break;
1308 }
1309 }
1310
1311 /* Advance */
1312 if (mb_encoding)
1313 {
1314 int w;
1315
1316 w = pg_encoding_dsplen(encoding, &wquery[qoffset]);
1317 /* treat any non-tab control chars as width 1 */
1318 if (w <= 0)
1319 w = 1;
1320 scroffset += w;
1321 qoffset += PQmblenBounded(&wquery[qoffset], encoding);
1322 }
1323 else
1324 {
1325 /* We assume wide chars only exist in multibyte encodings */
1326 scroffset++;
1327 qoffset++;
1328 }
1329 }
1330 /* Fix up if we didn't find an end-of-line after loc */
1331 if (iend < 0)
1332 {
1333 iend = cno; /* query length in chars, +1 */
1334 qidx[iend] = qoffset;
1335 scridx[iend] = scroffset;
1336 }
1337
1338 /* Print only if loc is within computed query length */
1339 if (loc <= cno)
1340 {
1341 /* If the line extracted is too long, we truncate it. */
1342 beg_trunc = false;
1343 end_trunc = false;
1344 if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
1345 {
1346 /*
1347 * We first truncate right if it is enough. This code might be
1348 * off a space or so on enforcing MIN_RIGHT_CUT if there's a wide
1349 * character right there, but that should be okay.
1350 */
1351 if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT)
1352 {
1353 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
1354 iend--;
1355 end_trunc = true;
1356 }
1357 else
1358 {
1359 /* Truncate right if not too close to loc. */
1360 while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend])
1361 {
1362 iend--;
1363 end_trunc = true;
1364 }
1365
1366 /* Truncate left if still too long. */
1367 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
1368 {
1369 ibeg++;
1370 beg_trunc = true;
1371 }
1372 }
1373 }
1374
1375 /* truncate working copy at desired endpoint */
1376 wquery[qidx[iend]] = '\0';
1377
1378 /* Begin building the finished message. */
1379 i = msg->len;
1380 appendPQExpBuffer(msg, libpq_gettext("LINE %d: "), loc_line);
1381 if (beg_trunc)
1382 appendPQExpBufferStr(msg, "...");
1383
1384 /*
1385 * While we have the prefix in the msg buffer, compute its screen
1386 * width.
1387 */
1388 scroffset = 0;
1389 for (; i < msg->len; i += PQmblenBounded(&msg->data[i], encoding))
1390 {
1391 int w = pg_encoding_dsplen(encoding, &msg->data[i]);
1392
1393 if (w <= 0)
1394 w = 1;
1395 scroffset += w;
1396 }
1397
1398 /* Finish up the LINE message line. */
1399 appendPQExpBufferStr(msg, &wquery[qidx[ibeg]]);
1400 if (end_trunc)
1401 appendPQExpBufferStr(msg, "...");
1402 appendPQExpBufferChar(msg, '\n');
1403
1404 /* Now emit the cursor marker line. */
1405 scroffset += scridx[loc] - scridx[ibeg];
1406 for (i = 0; i < scroffset; i++)
1407 appendPQExpBufferChar(msg, ' ');
1408 appendPQExpBufferChar(msg, '^');
1409 appendPQExpBufferChar(msg, '\n');
1410 }
1411
1412 /* Clean up. */
1413 free(scridx);
1414 free(qidx);
1415 free(wquery);
1416}
int PQmblenBounded(const char *s, int encoding)
Definition: fe-misc.c:1266
#define DISPLAY_SIZE
#define MIN_RIGHT_CUT
int32 encoding
Definition: pg_database.h:41
int pg_encoding_dsplen(int encoding, const char *mbstr)
Definition: wchar.c:2176
int pg_encoding_max_length(int encoding)
Definition: wchar.c:2213

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), PQExpBufferData::data, DISPLAY_SIZE, encoding, free, i, PQExpBufferData::len, libpq_gettext, malloc, MIN_RIGHT_CUT, pg_encoding_dsplen(), pg_encoding_max_length(), and PQmblenBounded().

Referenced by pqBuildErrorMessage3().