Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Enumerations | Functions | Variables

libpq-int.h File Reference

#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"
Include dependency graph for libpq-int.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

union  pgresult_data
struct  pgresParamDesc
struct  pgresAttValue
struct  pgMessageField
struct  PGNoticeHooks
struct  PGEvent
struct  pg_result
struct  PQEnvironmentOption
struct  pgParameterStatus
struct  pgLobjfuncs
struct  pgDataValue
struct  pg_conn
struct  pg_cancel

Defines

#define CMDSTATUS_LEN   64
#define NULL_LEN   (-1)
#define pglock_thread()   ((void) 0)
#define pgunlock_thread()   ((void) 0)
#define pqIsnonblocking(conn)   ((conn)->nonblocking)
#define libpq_gettext(x)   (x)
#define SOCK_ERRNO   errno
#define SOCK_STRERROR   pqStrerror
#define SOCK_ERRNO_SET(e)   (errno = (e))

Typedefs

typedef union pgresult_data PGresult_data
typedef struct pgresParamDesc PGresParamDesc
typedef struct pgresAttValue PGresAttValue
typedef struct pgMessageField PGMessageField
typedef struct PGEvent PGEvent
typedef struct PQEnvironmentOption PQEnvironmentOption
typedef struct pgParameterStatus pgParameterStatus
typedef struct pgLobjfuncs PGlobjfuncs
typedef struct pgDataValue PGdataValue

Enumerations

enum  PGAsyncStatusType {
  PGASYNC_IDLE, PGASYNC_BUSY, PGASYNC_READY, PGASYNC_COPY_IN,
  PGASYNC_COPY_OUT, PGASYNC_COPY_BOTH
}
enum  PGQueryClass { PGQUERY_SIMPLE, PGQUERY_EXTENDED, PGQUERY_PREPARE, PGQUERY_DESCRIBE }
enum  PGSetenvStatusType {
  SETENV_STATE_CLIENT_ENCODING_SEND, SETENV_STATE_CLIENT_ENCODING_WAIT, SETENV_STATE_OPTION_SEND, SETENV_STATE_OPTION_WAIT,
  SETENV_STATE_QUERY1_SEND, SETENV_STATE_QUERY1_WAIT, SETENV_STATE_QUERY2_SEND, SETENV_STATE_QUERY2_WAIT,
  SETENV_STATE_IDLE
}

Functions

void pqDropConnection (PGconn *conn)
int pqPacketSend (PGconn *conn, char pack_type, const void *buf, size_t buf_len)
bool pqGetHomeDirectory (char *buf, int bufsize)
void pqSetResultError (PGresult *res, const char *msg)
void pqCatenateResultError (PGresult *res, const char *msg)
void * pqResultAlloc (PGresult *res, size_t nBytes, bool isBinary)
char * pqResultStrdup (PGresult *res, const char *str)
void pqClearAsyncResult (PGconn *conn)
void pqSaveErrorResult (PGconn *conn)
PGresultpqPrepareAsyncResult (PGconn *conn)
void pqInternalNotice (const PGNoticeHooks *hooks, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE
void void pqSaveMessageField (PGresult *res, char code, const char *value)
void pqSaveParameterStatus (PGconn *conn, const char *name, const char *value)
int pqRowProcessor (PGconn *conn, const char **errmsgp)
void pqHandleSendFailure (PGconn *conn)
PostgresPollingStatusType pqSetenvPoll (PGconn *conn)
char * pqBuildStartupPacket2 (PGconn *conn, int *packetlen, const PQEnvironmentOption *options)
void pqParseInput2 (PGconn *conn)
int pqGetCopyData2 (PGconn *conn, char **buffer, int async)
int pqGetline2 (PGconn *conn, char *s, int maxlen)
int pqGetlineAsync2 (PGconn *conn, char *buffer, int bufsize)
int pqEndcopy2 (PGconn *conn)
PGresultpqFunctionCall2 (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)
void pqParseInput3 (PGconn *conn)
int pqGetErrorNotice3 (PGconn *conn, bool isError)
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)
int pqCheckOutBufferSpace (size_t bytes_needed, PGconn *conn)
int pqCheckInBufferSpace (size_t bytes_needed, PGconn *conn)
int pqGetc (char *result, PGconn *conn)
int pqPutc (char c, PGconn *conn)
int pqGets (PQExpBuffer buf, PGconn *conn)
int pqGets_append (PQExpBuffer buf, PGconn *conn)
int pqPuts (const char *s, PGconn *conn)
int pqGetnchar (char *s, size_t len, PGconn *conn)
int pqSkipnchar (size_t len, PGconn *conn)
int pqPutnchar (const char *s, size_t len, PGconn *conn)
int pqGetInt (int *result, size_t bytes, PGconn *conn)
int pqPutInt (int value, size_t bytes, PGconn *conn)
int pqPutMsgStart (char msg_type, bool force_len, PGconn *conn)
int pqPutMsgEnd (PGconn *conn)
int pqReadData (PGconn *conn)
int pqFlush (PGconn *conn)
int pqWait (int forRead, int forWrite, PGconn *conn)
int pqWaitTimed (int forRead, int forWrite, PGconn *conn, time_t finish_time)
int pqReadReady (PGconn *conn)
int pqWriteReady (PGconn *conn)
int pqsecure_initialize (PGconn *)
void pqsecure_destroy (void)
PostgresPollingStatusType pqsecure_open_client (PGconn *)
void pqsecure_close (PGconn *)
ssize_t pqsecure_read (PGconn *, void *ptr, size_t len)
ssize_t pqsecure_write (PGconn *, const void *ptr, size_t len)

Variables

char *const pgresStatus []

Define Documentation

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

#define pqIsnonblocking (   conn  )     ((conn)->nonblocking)
#define SOCK_ERRNO   errno
#define SOCK_ERRNO_SET (   e  )     (errno = (e))

Definition at line 636 of file libpq-int.h.

Referenced by internal_cancel(), pqsecure_read(), and pqsecure_write().

#define SOCK_STRERROR   pqStrerror

Typedef Documentation

typedef struct pgDataValue PGdataValue
typedef struct PGEvent PGEvent
typedef struct pgLobjfuncs PGlobjfuncs
typedef struct pgresAttValue PGresAttValue

Definition at line 103 of file libpq-int.h.


Enumeration Type Documentation

Enumerator:
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;

Enumerator:
PGQUERY_SIMPLE 
PGQUERY_EXTENDED 
PGQUERY_PREPARE 
PGQUERY_DESCRIBE 

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;

Enumerator:
SETENV_STATE_CLIENT_ENCODING_SEND 
SETENV_STATE_CLIENT_ENCODING_WAIT 
SETENV_STATE_OPTION_SEND 
SETENV_STATE_OPTION_WAIT 
SETENV_STATE_QUERY1_SEND 
SETENV_STATE_QUERY1_WAIT 
SETENV_STATE_QUERY2_SEND 
SETENV_STATE_QUERY2_WAIT 
SETENV_STATE_IDLE 

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;


Function Documentation

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

{
    if (conn->inCursor >= conn->inEnd)
        return EOF;

    *result = conn->inBuffer[conn->inCursor++];

    if (conn->Pfdebug)
        fprintf(conn->Pfdebug, "From backend> %c\n", *result);

    return 0;
}

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;
    }
}

int pqGetErrorNotice3 ( PGconn conn,
bool  isError 
)

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 
)
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;
        }
    }
}

PGresult* pqPrepareAsyncResult ( PGconn conn  ) 

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;
}

int pqPutMsgStart ( char  msg_type,
bool  force_len,
PGconn conn 
)

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);
}

void* pqResultAlloc ( PGresult res,
size_t  nBytes,
bool  isBinary 
)

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

{
#ifdef USE_SSL
    if (conn->ssl)
        close_SSL(conn);
#endif
}

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

{
    if (len > (size_t) (conn->inEnd - conn->inCursor))
        return EOF;

    if (conn->Pfdebug)
    {
        fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len);
        fputnbytes(conn->Pfdebug, conn->inBuffer + conn->inCursor, len);
        fprintf(conn->Pfdebug, "\n");
    }

    conn->inCursor += len;

    return 0;
}

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);
}


Variable Documentation

char* const pgresStatus[]

Definition at line 32 of file fe-exec.c.

Referenced by PQresStatus().