Update libpq to make new features of FE/BE protocol available to
client applications. Some editorial work on libpq.sgml, too.
This commit is contained in:
parent
b8d601e735
commit
efc3a25bb0
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/lobj.sgml,v 1.28 2003/03/13 01:30:28 petere Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/lobj.sgml,v 1.29 2003/06/21 21:51:33 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="largeObjects">
|
<chapter id="largeObjects">
|
||||||
|
@ -181,7 +181,8 @@ int lo_open(PGconn *conn, Oid lobjId, int mode);
|
||||||
<function>lo_open</function> returns a large object descriptor
|
<function>lo_open</function> returns a large object descriptor
|
||||||
for later use in <function>lo_read</function>, <function>lo_write</function>,
|
for later use in <function>lo_read</function>, <function>lo_write</function>,
|
||||||
<function>lo_lseek</function>, <function>lo_tell</function>, and
|
<function>lo_lseek</function>, <function>lo_tell</function>, and
|
||||||
<function>lo_close</function>.
|
<function>lo_close</function>. The descriptor is only valid for
|
||||||
|
the duration of the current transaction.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
@ -256,6 +257,11 @@ int lo_close(PGconn *conn, int fd);
|
||||||
<function>lo_open</function>. On success, <function>lo_close</function>
|
<function>lo_open</function>. On success, <function>lo_close</function>
|
||||||
returns zero. On error, the return value is negative.
|
returns zero. On error, the return value is negative.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Any large object descriptors that remain open at the end of a
|
||||||
|
transaction will be closed automatically.
|
||||||
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2>
|
<sect2>
|
||||||
|
@ -296,6 +302,14 @@ SELECT lo_export(image.raster, '/tmp/motd') FROM image
|
||||||
WHERE name = 'beautiful image';
|
WHERE name = 'beautiful image';
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These functions read and write files in the server's filesystem, using the
|
||||||
|
permissions of the database's owning user. Therefore, their use is restricted
|
||||||
|
to superusers. (In contrast, the client-side import and export functions
|
||||||
|
read and write files in the client's filesystem, using the permissions of
|
||||||
|
the client program. Their use is not restricted.)
|
||||||
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="lo-examplesect">
|
<sect1 id="lo-examplesect">
|
||||||
|
|
|
@ -97,6 +97,20 @@ EXPORTS
|
||||||
_pg_utf_mblen @ 93
|
_pg_utf_mblen @ 93
|
||||||
_PQunescapeBytea @ 94
|
_PQunescapeBytea @ 94
|
||||||
_PQfreemem @ 95
|
_PQfreemem @ 95
|
||||||
|
_PQtransactionStatus @ 96
|
||||||
|
_PQparameterStatus @ 97
|
||||||
|
_PQprotocolVersion @ 98
|
||||||
|
_PQsetErrorVerbosity @ 99
|
||||||
|
_PQsetNoticeReceiver @ 100
|
||||||
|
_PQexecParams @ 101
|
||||||
|
_PQsendQueryParams @ 102
|
||||||
|
_PQputCopyData @ 103
|
||||||
|
_PQputCopyEnd @ 104
|
||||||
|
_PQgetCopyData @ 105
|
||||||
|
_PQresultErrorField @ 106
|
||||||
|
_PQftable @ 107
|
||||||
|
_PQftablecol @ 108
|
||||||
|
_PQfformat @ 109
|
||||||
|
|
||||||
; Aliases for MS compatible names
|
; Aliases for MS compatible names
|
||||||
PQconnectdb = _PQconnectdb
|
PQconnectdb = _PQconnectdb
|
||||||
|
@ -194,4 +208,17 @@ EXPORTS
|
||||||
pg_utf_mblen = _pg_utf_mblen
|
pg_utf_mblen = _pg_utf_mblen
|
||||||
PQunescapeBytea = _PQunescapeBytea
|
PQunescapeBytea = _PQunescapeBytea
|
||||||
PQfreemem = _PQfreemem
|
PQfreemem = _PQfreemem
|
||||||
|
PQtransactionStatus = _PQtransactionStatus
|
||||||
|
PQparameterStatus = _PQparameterStatus
|
||||||
|
PQprotocolVersion = _PQprotocolVersion
|
||||||
|
PQsetErrorVerbosity = _PQsetErrorVerbosity
|
||||||
|
PQsetNoticeReceiver = _PQsetNoticeReceiver
|
||||||
|
PQexecParams = _PQexecParams
|
||||||
|
PQsendQueryParams = _PQsendQueryParams
|
||||||
|
PQputCopyData = _PQputCopyData
|
||||||
|
PQputCopyEnd = _PQputCopyEnd
|
||||||
|
PQgetCopyData = _PQgetCopyData
|
||||||
|
PQresultErrorField = _PQresultErrorField
|
||||||
|
PQftable = _PQftable
|
||||||
|
PQftablecol = _PQftablecol
|
||||||
|
PQfformat = _PQfformat
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.249 2003/06/20 04:09:12 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.250 2003/06/21 21:51:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -176,6 +176,7 @@ static PQconninfoOption *conninfo_parse(const char *conninfo,
|
||||||
PQExpBuffer errorMessage);
|
PQExpBuffer errorMessage);
|
||||||
static char *conninfo_getval(PQconninfoOption *connOptions,
|
static char *conninfo_getval(PQconninfoOption *connOptions,
|
||||||
const char *keyword);
|
const char *keyword);
|
||||||
|
static void defaultNoticeReceiver(void *arg, const PGresult *res);
|
||||||
static void defaultNoticeProcessor(void *arg, const char *message);
|
static void defaultNoticeProcessor(void *arg, const char *message);
|
||||||
static int parseServiceInfo(PQconninfoOption *options,
|
static int parseServiceInfo(PQconninfoOption *options,
|
||||||
PQExpBuffer errorMessage);
|
PQExpBuffer errorMessage);
|
||||||
|
@ -1804,11 +1805,14 @@ makeEmptyPGconn(void)
|
||||||
/* Zero all pointers and booleans */
|
/* Zero all pointers and booleans */
|
||||||
MemSet((char *) conn, 0, sizeof(PGconn));
|
MemSet((char *) conn, 0, sizeof(PGconn));
|
||||||
|
|
||||||
conn->noticeHook = defaultNoticeProcessor;
|
conn->noticeHooks.noticeRec = defaultNoticeReceiver;
|
||||||
|
conn->noticeHooks.noticeProc = defaultNoticeProcessor;
|
||||||
conn->status = CONNECTION_BAD;
|
conn->status = CONNECTION_BAD;
|
||||||
conn->asyncStatus = PGASYNC_IDLE;
|
conn->asyncStatus = PGASYNC_IDLE;
|
||||||
|
conn->xactStatus = PQTRANS_IDLE;
|
||||||
conn->setenv_state = SETENV_STATE_IDLE;
|
conn->setenv_state = SETENV_STATE_IDLE;
|
||||||
conn->client_encoding = PG_SQL_ASCII;
|
conn->client_encoding = PG_SQL_ASCII;
|
||||||
|
conn->verbosity = PQERRORS_DEFAULT;
|
||||||
conn->notifyList = DLNewList();
|
conn->notifyList = DLNewList();
|
||||||
conn->sock = -1;
|
conn->sock = -1;
|
||||||
#ifdef USE_SSL
|
#ifdef USE_SSL
|
||||||
|
@ -1850,7 +1854,6 @@ makeEmptyPGconn(void)
|
||||||
/*
|
/*
|
||||||
* freePGconn
|
* freePGconn
|
||||||
* - free the PGconn data structure
|
* - free the PGconn data structure
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
freePGconn(PGconn *conn)
|
freePGconn(PGconn *conn)
|
||||||
|
@ -1899,9 +1902,9 @@ freePGconn(PGconn *conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
closePGconn
|
* closePGconn
|
||||||
- properly close a connection to the backend
|
* - properly close a connection to the backend
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
closePGconn(PGconn *conn)
|
closePGconn(PGconn *conn)
|
||||||
{
|
{
|
||||||
|
@ -2662,6 +2665,41 @@ PQstatus(const PGconn *conn)
|
||||||
return conn->status;
|
return conn->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PGTransactionStatusType
|
||||||
|
PQtransactionStatus(const PGconn *conn)
|
||||||
|
{
|
||||||
|
if (!conn || conn->status != CONNECTION_OK)
|
||||||
|
return PQTRANS_UNKNOWN;
|
||||||
|
if (conn->asyncStatus != PGASYNC_IDLE)
|
||||||
|
return PQTRANS_ACTIVE;
|
||||||
|
return conn->xactStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
PQparameterStatus(const PGconn *conn, const char *paramName)
|
||||||
|
{
|
||||||
|
const pgParameterStatus *pstatus;
|
||||||
|
|
||||||
|
if (!conn || !paramName)
|
||||||
|
return NULL;
|
||||||
|
for (pstatus = conn->pstatus; pstatus != NULL; pstatus = pstatus->next)
|
||||||
|
{
|
||||||
|
if (strcmp(pstatus->name, paramName) == 0)
|
||||||
|
return pstatus->value;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PQprotocolVersion(const PGconn *conn)
|
||||||
|
{
|
||||||
|
if (!conn)
|
||||||
|
return 0;
|
||||||
|
if (conn->status == CONNECTION_BAD)
|
||||||
|
return 0;
|
||||||
|
return PG_PROTOCOL_MAJOR(conn->pversion);
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
PQerrorMessage(const PGconn *conn)
|
PQerrorMessage(const PGconn *conn)
|
||||||
{
|
{
|
||||||
|
@ -2731,11 +2769,22 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PGVerbosity
|
||||||
|
PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity)
|
||||||
|
{
|
||||||
|
PGVerbosity old;
|
||||||
|
|
||||||
|
if (!conn)
|
||||||
|
return PQERRORS_DEFAULT;
|
||||||
|
old = conn->verbosity;
|
||||||
|
conn->verbosity = verbosity;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PQtrace(PGconn *conn, FILE *debug_port)
|
PQtrace(PGconn *conn, FILE *debug_port)
|
||||||
{
|
{
|
||||||
if (conn == NULL ||
|
if (conn == NULL)
|
||||||
conn->status == CONNECTION_BAD)
|
|
||||||
return;
|
return;
|
||||||
PQuntrace(conn);
|
PQuntrace(conn);
|
||||||
conn->Pfdebug = debug_port;
|
conn->Pfdebug = debug_port;
|
||||||
|
@ -2744,7 +2793,6 @@ PQtrace(PGconn *conn, FILE *debug_port)
|
||||||
void
|
void
|
||||||
PQuntrace(PGconn *conn)
|
PQuntrace(PGconn *conn)
|
||||||
{
|
{
|
||||||
/* note: better allow untrace even when connection bad */
|
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return;
|
return;
|
||||||
if (conn->Pfdebug)
|
if (conn->Pfdebug)
|
||||||
|
@ -2754,6 +2802,23 @@ PQuntrace(PGconn *conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PQnoticeReceiver
|
||||||
|
PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg)
|
||||||
|
{
|
||||||
|
PQnoticeReceiver old;
|
||||||
|
|
||||||
|
if (conn == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
old = conn->noticeHooks.noticeRec;
|
||||||
|
if (proc)
|
||||||
|
{
|
||||||
|
conn->noticeHooks.noticeRec = proc;
|
||||||
|
conn->noticeHooks.noticeRecArg = arg;
|
||||||
|
}
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
PQnoticeProcessor
|
PQnoticeProcessor
|
||||||
PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
|
PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
|
||||||
{
|
{
|
||||||
|
@ -2762,22 +2827,35 @@ PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
old = conn->noticeHook;
|
old = conn->noticeHooks.noticeProc;
|
||||||
if (proc)
|
if (proc)
|
||||||
{
|
{
|
||||||
conn->noticeHook = proc;
|
conn->noticeHooks.noticeProc = proc;
|
||||||
conn->noticeArg = arg;
|
conn->noticeHooks.noticeProcArg = arg;
|
||||||
}
|
}
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The default notice/error message processor just prints the
|
* The default notice message receiver just gets the standard notice text
|
||||||
|
* and sends it to the notice processor. This two-level setup exists
|
||||||
|
* mostly for backwards compatibility; perhaps we should deprecate use of
|
||||||
|
* PQsetNoticeProcessor?
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
defaultNoticeReceiver(void *arg, const PGresult *res)
|
||||||
|
{
|
||||||
|
(void) arg; /* not used */
|
||||||
|
(*res->noticeHooks.noticeProc) (res->noticeHooks.noticeProcArg,
|
||||||
|
PQresultErrorMessage(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The default notice message processor just prints the
|
||||||
* message on stderr. Applications can override this if they
|
* message on stderr. Applications can override this if they
|
||||||
* want the messages to go elsewhere (a window, for example).
|
* want the messages to go elsewhere (a window, for example).
|
||||||
* Note that simply discarding notices is probably a bad idea.
|
* Note that simply discarding notices is probably a bad idea.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
defaultNoticeProcessor(void *arg, const char *message)
|
defaultNoticeProcessor(void *arg, const char *message)
|
||||||
{
|
{
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,7 +23,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.96 2003/06/14 17:49:54 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.97 2003/06/21 21:51:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -197,7 +197,7 @@ pqPutnchar(const char *s, size_t len, PGconn *conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pgGetInt
|
* pqGetInt
|
||||||
* read a 2 or 4 byte integer and convert from network byte order
|
* read a 2 or 4 byte integer and convert from network byte order
|
||||||
* to local byte order
|
* to local byte order
|
||||||
*/
|
*/
|
||||||
|
@ -226,7 +226,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
snprintf(noticeBuf, sizeof(noticeBuf),
|
snprintf(noticeBuf, sizeof(noticeBuf),
|
||||||
libpq_gettext("integer of size %lu not supported by pqGetInt\n"),
|
libpq_gettext("integer of size %lu not supported by pqGetInt"),
|
||||||
(unsigned long) bytes);
|
(unsigned long) bytes);
|
||||||
PGDONOTICE(conn, noticeBuf);
|
PGDONOTICE(conn, noticeBuf);
|
||||||
return EOF;
|
return EOF;
|
||||||
|
@ -239,7 +239,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pgPutInt
|
* pqPutInt
|
||||||
* write an integer of 2 or 4 bytes, converting from host byte order
|
* write an integer of 2 or 4 bytes, converting from host byte order
|
||||||
* to network byte order.
|
* to network byte order.
|
||||||
*/
|
*/
|
||||||
|
@ -264,7 +264,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
snprintf(noticeBuf, sizeof(noticeBuf),
|
snprintf(noticeBuf, sizeof(noticeBuf),
|
||||||
libpq_gettext("integer of size %lu not supported by pqPutInt\n"),
|
libpq_gettext("integer of size %lu not supported by pqPutInt"),
|
||||||
(unsigned long) bytes);
|
(unsigned long) bytes);
|
||||||
PGDONOTICE(conn, noticeBuf);
|
PGDONOTICE(conn, noticeBuf);
|
||||||
return EOF;
|
return EOF;
|
||||||
|
@ -282,7 +282,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
|
||||||
*
|
*
|
||||||
* Returns 0 on success, EOF if failed to enlarge buffer
|
* Returns 0 on success, EOF if failed to enlarge buffer
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
|
pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
|
||||||
{
|
{
|
||||||
int newsize = conn->outBufSize;
|
int newsize = conn->outBufSize;
|
||||||
|
@ -748,7 +748,7 @@ pqSendSome(PGconn *conn, int len)
|
||||||
if (sent < 0)
|
if (sent < 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Anything except EAGAIN or EWOULDBLOCK is trouble. If it's
|
* Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble. If it's
|
||||||
* EPIPE or ECONNRESET, assume we've lost the backend
|
* EPIPE or ECONNRESET, assume we've lost the backend
|
||||||
* connection permanently.
|
* connection permanently.
|
||||||
*/
|
*/
|
||||||
|
@ -804,25 +804,17 @@ pqSendSome(PGconn *conn, int len)
|
||||||
|
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
{
|
{
|
||||||
/* We didn't send it all, wait till we can send more */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the socket is in non-blocking mode we may need to abort
|
* We didn't send it all, wait till we can send more.
|
||||||
* here and return 1 to indicate that data is still pending.
|
*
|
||||||
|
* If the connection is in non-blocking mode we don't wait,
|
||||||
|
* but return 1 to indicate that data is still pending.
|
||||||
*/
|
*/
|
||||||
#ifdef USE_SSL
|
if (pqIsnonblocking(conn))
|
||||||
/* can't do anything for our SSL users yet */
|
|
||||||
if (conn->ssl == NULL)
|
|
||||||
{
|
{
|
||||||
#endif
|
result = 1;
|
||||||
if (pqIsnonblocking(conn))
|
break;
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#ifdef USE_SSL
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pqWait(FALSE, TRUE, conn))
|
if (pqWait(FALSE, TRUE, conn))
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-protocol2.c,v 1.1 2003/06/08 17:43:00 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-protocol2.c,v 1.2 2003/06/21 21:51:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -38,6 +38,7 @@
|
||||||
static int getRowDescriptions(PGconn *conn);
|
static int getRowDescriptions(PGconn *conn);
|
||||||
static int getAnotherTuple(PGconn *conn, bool binary);
|
static int getAnotherTuple(PGconn *conn, bool binary);
|
||||||
static int pqGetErrorNotice2(PGconn *conn, bool isError);
|
static int pqGetErrorNotice2(PGconn *conn, bool isError);
|
||||||
|
static void checkXactStatus(PGconn *conn, const char *cmdTag);
|
||||||
static int getNotify(PGconn *conn);
|
static int getNotify(PGconn *conn);
|
||||||
|
|
||||||
|
|
||||||
|
@ -312,7 +313,7 @@ pqSetenvPoll(PGconn *conn)
|
||||||
val);
|
val);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
val = pqGetParameterStatus(conn, "server_encoding");
|
val = PQparameterStatus(conn, "server_encoding");
|
||||||
if (val && *val)
|
if (val && *val)
|
||||||
pqSaveParameterStatus(conn, "client_encoding",
|
pqSaveParameterStatus(conn, "client_encoding",
|
||||||
val);
|
val);
|
||||||
|
@ -424,7 +425,7 @@ pqParseInput2(PGconn *conn)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
||||||
libpq_gettext("message type 0x%02x arrived from server while idle\n"),
|
libpq_gettext("message type 0x%02x arrived from server while idle"),
|
||||||
id);
|
id);
|
||||||
PGDONOTICE(conn, noticeWorkspace);
|
PGDONOTICE(conn, noticeWorkspace);
|
||||||
/* Discard the unexpected message; good idea?? */
|
/* Discard the unexpected message; good idea?? */
|
||||||
|
@ -447,6 +448,7 @@ pqParseInput2(PGconn *conn)
|
||||||
PGRES_COMMAND_OK);
|
PGRES_COMMAND_OK);
|
||||||
strncpy(conn->result->cmdStatus, conn->workBuffer.data,
|
strncpy(conn->result->cmdStatus, conn->workBuffer.data,
|
||||||
CMDSTATUS_LEN);
|
CMDSTATUS_LEN);
|
||||||
|
checkXactStatus(conn, conn->workBuffer.data);
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
break;
|
break;
|
||||||
case 'E': /* error return */
|
case 'E': /* error return */
|
||||||
|
@ -464,7 +466,7 @@ pqParseInput2(PGconn *conn)
|
||||||
if (id != '\0')
|
if (id != '\0')
|
||||||
{
|
{
|
||||||
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
||||||
libpq_gettext("unexpected character %c following empty query response (\"I\" message)\n"),
|
libpq_gettext("unexpected character %c following empty query response (\"I\" message)"),
|
||||||
id);
|
id);
|
||||||
PGDONOTICE(conn, noticeWorkspace);
|
PGDONOTICE(conn, noticeWorkspace);
|
||||||
}
|
}
|
||||||
|
@ -521,7 +523,7 @@ pqParseInput2(PGconn *conn)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
||||||
libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n"));
|
libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)"));
|
||||||
PGDONOTICE(conn, noticeWorkspace);
|
PGDONOTICE(conn, noticeWorkspace);
|
||||||
/* Discard the unexpected message; good idea?? */
|
/* Discard the unexpected message; good idea?? */
|
||||||
conn->inStart = conn->inEnd;
|
conn->inStart = conn->inEnd;
|
||||||
|
@ -538,7 +540,7 @@ pqParseInput2(PGconn *conn)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
||||||
libpq_gettext("server sent binary data (\"B\" message) without prior row description (\"T\" message)\n"));
|
libpq_gettext("server sent binary data (\"B\" message) without prior row description (\"T\" message)"));
|
||||||
PGDONOTICE(conn, noticeWorkspace);
|
PGDONOTICE(conn, noticeWorkspace);
|
||||||
/* Discard the unexpected message; good idea?? */
|
/* Discard the unexpected message; good idea?? */
|
||||||
conn->inStart = conn->inEnd;
|
conn->inStart = conn->inEnd;
|
||||||
|
@ -628,6 +630,9 @@ getRowDescriptions(PGconn *conn)
|
||||||
|
|
||||||
result->attDescs[i].name = pqResultStrdup(result,
|
result->attDescs[i].name = pqResultStrdup(result,
|
||||||
conn->workBuffer.data);
|
conn->workBuffer.data);
|
||||||
|
result->attDescs[i].tableid = 0;
|
||||||
|
result->attDescs[i].columnid = 0;
|
||||||
|
result->attDescs[i].format = 0;
|
||||||
result->attDescs[i].typid = typid;
|
result->attDescs[i].typid = typid;
|
||||||
result->attDescs[i].typlen = typlen;
|
result->attDescs[i].typlen = typlen;
|
||||||
result->attDescs[i].atttypmod = atttypmod;
|
result->attDescs[i].atttypmod = atttypmod;
|
||||||
|
@ -674,6 +679,15 @@ getAnotherTuple(PGconn *conn, bool binary)
|
||||||
if (conn->curTuple == NULL)
|
if (conn->curTuple == NULL)
|
||||||
goto outOfMemory;
|
goto outOfMemory;
|
||||||
MemSet((char *) conn->curTuple, 0, nfields * sizeof(PGresAttValue));
|
MemSet((char *) conn->curTuple, 0, nfields * sizeof(PGresAttValue));
|
||||||
|
/*
|
||||||
|
* If it's binary, fix the column format indicators. We assume
|
||||||
|
* the backend will consistently send either B or D, not a mix.
|
||||||
|
*/
|
||||||
|
if (binary)
|
||||||
|
{
|
||||||
|
for (i = 0; i < nfields; i++)
|
||||||
|
result->attDescs[i].format = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tup = conn->curTuple;
|
tup = conn->curTuple;
|
||||||
|
|
||||||
|
@ -778,6 +792,8 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
|
||||||
{
|
{
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
PQExpBufferData workBuf;
|
PQExpBufferData workBuf;
|
||||||
|
char *startp;
|
||||||
|
char *splitp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since the message might be pretty long, we create a temporary
|
* Since the message might be pretty long, we create a temporary
|
||||||
|
@ -800,19 +816,63 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
|
||||||
res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
|
res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
|
||||||
res->errMsg = pqResultStrdup(res, workBuf.data);
|
res->errMsg = pqResultStrdup(res, workBuf.data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Break the message into fields. We can't do very much here, but we
|
||||||
|
* can split the severity code off, and remove trailing newlines. Also,
|
||||||
|
* we use the heuristic that the primary message extends only to the
|
||||||
|
* first newline --- anything after that is detail message. (In some
|
||||||
|
* cases it'd be better classed as hint, but we can hardly be expected
|
||||||
|
* to guess that here.)
|
||||||
|
*/
|
||||||
|
while (workBuf.len > 0 && workBuf.data[workBuf.len-1] == '\n')
|
||||||
|
workBuf.data[--workBuf.len] = '\0';
|
||||||
|
splitp = strstr(workBuf.data, ": ");
|
||||||
|
if (splitp)
|
||||||
|
{
|
||||||
|
/* what comes before the colon is severity */
|
||||||
|
*splitp = '\0';
|
||||||
|
pqSaveMessageField(res, 'S', workBuf.data);
|
||||||
|
startp = splitp + 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* can't find a colon? oh well... */
|
||||||
|
startp = workBuf.data;
|
||||||
|
}
|
||||||
|
splitp = strchr(startp, '\n');
|
||||||
|
if (splitp)
|
||||||
|
{
|
||||||
|
/* what comes before the newline is primary message */
|
||||||
|
*splitp++ = '\0';
|
||||||
|
pqSaveMessageField(res, 'M', startp);
|
||||||
|
/* the rest is detail; strip any leading whitespace */
|
||||||
|
while (*splitp && isspace((unsigned char) *splitp))
|
||||||
|
splitp++;
|
||||||
|
pqSaveMessageField(res, 'D', splitp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* single-line message, so all primary */
|
||||||
|
pqSaveMessageField(res, 'M', startp);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Either save error as current async result, or just emit the notice.
|
* Either save error as current async result, or just emit the notice.
|
||||||
|
* Also, if it's an error and we were in a transaction block, assume
|
||||||
|
* the server has now gone to error-in-transaction state.
|
||||||
*/
|
*/
|
||||||
if (isError)
|
if (isError)
|
||||||
{
|
{
|
||||||
pqClearAsyncResult(conn);
|
pqClearAsyncResult(conn);
|
||||||
conn->result = res;
|
conn->result = res;
|
||||||
resetPQExpBuffer(&conn->errorMessage);
|
resetPQExpBuffer(&conn->errorMessage);
|
||||||
appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
|
appendPQExpBufferStr(&conn->errorMessage, res->errMsg);
|
||||||
|
if (conn->xactStatus == PQTRANS_INTRANS)
|
||||||
|
conn->xactStatus = PQTRANS_INERROR;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PGDONOTICE(conn, workBuf.data);
|
(*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,6 +880,37 @@ pqGetErrorNotice2(PGconn *conn, bool isError)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* checkXactStatus - attempt to track transaction-block status of server
|
||||||
|
*
|
||||||
|
* This is called each time we receive a command-complete message. By
|
||||||
|
* watching for messages from BEGIN/COMMIT/ROLLBACK commands, we can do
|
||||||
|
* a passable job of tracking the server's xact status. BUT: this does
|
||||||
|
* not work at all on 7.3 servers with AUTOCOMMIT OFF. (Man, was that
|
||||||
|
* feature ever a mistake.) Caveat user.
|
||||||
|
*
|
||||||
|
* The tags known here are all those used as far back as 7.0; is it worth
|
||||||
|
* adding those from even-older servers?
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
checkXactStatus(PGconn *conn, const char *cmdTag)
|
||||||
|
{
|
||||||
|
if (strcmp(cmdTag, "BEGIN") == 0)
|
||||||
|
conn->xactStatus = PQTRANS_INTRANS;
|
||||||
|
else if (strcmp(cmdTag, "COMMIT") == 0)
|
||||||
|
conn->xactStatus = PQTRANS_IDLE;
|
||||||
|
else if (strcmp(cmdTag, "ROLLBACK") == 0)
|
||||||
|
conn->xactStatus = PQTRANS_IDLE;
|
||||||
|
else if (strcmp(cmdTag, "START TRANSACTION") == 0) /* 7.3 only */
|
||||||
|
conn->xactStatus = PQTRANS_INTRANS;
|
||||||
|
/*
|
||||||
|
* Normally we get into INERROR state by detecting an Error message.
|
||||||
|
* However, if we see one of these tags then we know for sure the
|
||||||
|
* server is in abort state ...
|
||||||
|
*/
|
||||||
|
else if (strcmp(cmdTag, "*ABORT STATE*") == 0) /* pre-7.3 only */
|
||||||
|
conn->xactStatus = PQTRANS_INERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attempt to read a Notify response message.
|
* Attempt to read a Notify response message.
|
||||||
|
@ -832,6 +923,7 @@ static int
|
||||||
getNotify(PGconn *conn)
|
getNotify(PGconn *conn)
|
||||||
{
|
{
|
||||||
int be_pid;
|
int be_pid;
|
||||||
|
int nmlen;
|
||||||
PGnotify *newNotify;
|
PGnotify *newNotify;
|
||||||
|
|
||||||
if (pqGetInt(&be_pid, 4, conn))
|
if (pqGetInt(&be_pid, 4, conn))
|
||||||
|
@ -844,12 +936,14 @@ getNotify(PGconn *conn)
|
||||||
* can all be freed at once. We don't use NAMEDATALEN because we
|
* can all be freed at once. We don't use NAMEDATALEN because we
|
||||||
* don't want to tie this interface to a specific server name length.
|
* don't want to tie this interface to a specific server name length.
|
||||||
*/
|
*/
|
||||||
newNotify = (PGnotify *) malloc(sizeof(PGnotify) +
|
nmlen = strlen(conn->workBuffer.data);
|
||||||
strlen(conn->workBuffer.data) +1);
|
newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + 1);
|
||||||
if (newNotify)
|
if (newNotify)
|
||||||
{
|
{
|
||||||
newNotify->relname = (char *) newNotify + sizeof(PGnotify);
|
newNotify->relname = (char *) newNotify + sizeof(PGnotify);
|
||||||
strcpy(newNotify->relname, conn->workBuffer.data);
|
strcpy(newNotify->relname, conn->workBuffer.data);
|
||||||
|
/* fake up an empty-string extra field */
|
||||||
|
newNotify->extra = newNotify->relname + nmlen;
|
||||||
newNotify->be_pid = be_pid;
|
newNotify->be_pid = be_pid;
|
||||||
DLAddTail(conn->notifyList, DLNewElem(newNotify));
|
DLAddTail(conn->notifyList, DLNewElem(newNotify));
|
||||||
}
|
}
|
||||||
|
@ -858,6 +952,84 @@ getNotify(PGconn *conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PQgetCopyData - read a row of data from the backend during COPY OUT
|
||||||
|
*
|
||||||
|
* If successful, sets *buffer to point to a malloc'd row of data, and
|
||||||
|
* returns row length (always > 0) as result.
|
||||||
|
* Returns 0 if no row available yet (only possible if async is true),
|
||||||
|
* -1 if end of copy (consult PQgetResult), or -2 if error (consult
|
||||||
|
* PQerrorMessage).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
pqGetCopyData2(PGconn *conn, char **buffer, int async)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PQgetline - gets a newline-terminated string from the backend.
|
* PQgetline - gets a newline-terminated string from the backend.
|
||||||
*
|
*
|
||||||
|
@ -1020,7 +1192,7 @@ pqEndcopy2(PGconn *conn)
|
||||||
if (conn->errorMessage.len > 0)
|
if (conn->errorMessage.len > 0)
|
||||||
PGDONOTICE(conn, conn->errorMessage.data);
|
PGDONOTICE(conn, conn->errorMessage.data);
|
||||||
|
|
||||||
PGDONOTICE(conn, libpq_gettext("lost synchronization with server, resetting connection\n"));
|
PGDONOTICE(conn, libpq_gettext("lost synchronization with server, resetting connection"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Users doing non-blocking connections need to handle the reset
|
* Users doing non-blocking connections need to handle the reset
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.1 2003/06/08 17:43:00 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.2 2003/06/21 21:51:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -40,6 +40,8 @@ static int getRowDescriptions(PGconn *conn);
|
||||||
static int getAnotherTuple(PGconn *conn, int msgLength);
|
static int getAnotherTuple(PGconn *conn, int msgLength);
|
||||||
static int getParameterStatus(PGconn *conn);
|
static int getParameterStatus(PGconn *conn);
|
||||||
static int getNotify(PGconn *conn);
|
static int getNotify(PGconn *conn);
|
||||||
|
static int getCopyStart(PGconn *conn, ExecStatusType copytype);
|
||||||
|
static int getReadyForQuery(PGconn *conn);
|
||||||
static int build_startup_packet(const PGconn *conn, char *packet,
|
static int build_startup_packet(const PGconn *conn, char *packet,
|
||||||
const PQEnvironmentOption *options);
|
const PQEnvironmentOption *options);
|
||||||
|
|
||||||
|
@ -171,7 +173,7 @@ pqParseInput3(PGconn *conn)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
snprintf(noticeWorkspace, sizeof(noticeWorkspace),
|
||||||
libpq_gettext("message type 0x%02x arrived from server while idle\n"),
|
libpq_gettext("message type 0x%02x arrived from server while idle"),
|
||||||
id);
|
id);
|
||||||
PGDONOTICE(conn, noticeWorkspace);
|
PGDONOTICE(conn, noticeWorkspace);
|
||||||
/* Discard the unexpected message */
|
/* Discard the unexpected message */
|
||||||
|
@ -201,7 +203,7 @@ pqParseInput3(PGconn *conn)
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
break;
|
break;
|
||||||
case 'Z': /* backend is ready for new query */
|
case 'Z': /* backend is ready for new query */
|
||||||
if (pqGetc(&conn->xact_status, conn))
|
if (getReadyForQuery(conn))
|
||||||
return;
|
return;
|
||||||
conn->asyncStatus = PGASYNC_IDLE;
|
conn->asyncStatus = PGASYNC_IDLE;
|
||||||
break;
|
break;
|
||||||
|
@ -211,6 +213,11 @@ pqParseInput3(PGconn *conn)
|
||||||
PGRES_EMPTY_QUERY);
|
PGRES_EMPTY_QUERY);
|
||||||
conn->asyncStatus = PGASYNC_READY;
|
conn->asyncStatus = PGASYNC_READY;
|
||||||
break;
|
break;
|
||||||
|
case '1': /* Parse Complete */
|
||||||
|
case '2': /* Bind Complete */
|
||||||
|
case '3': /* Close Complete */
|
||||||
|
/* Nothing to do for these message types */
|
||||||
|
break;
|
||||||
case 'S': /* parameter status */
|
case 'S': /* parameter status */
|
||||||
if (getParameterStatus(conn))
|
if (getParameterStatus(conn))
|
||||||
return;
|
return;
|
||||||
|
@ -276,17 +283,13 @@ pqParseInput3(PGconn *conn)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'G': /* Start Copy In */
|
case 'G': /* Start Copy In */
|
||||||
if (pqGetc(&conn->copy_is_binary, conn))
|
if (getCopyStart(conn, PGRES_COPY_IN))
|
||||||
return;
|
return;
|
||||||
/* XXX we currently ignore the rest of the message */
|
|
||||||
conn->inCursor = conn->inStart + 5 + msgLength;
|
|
||||||
conn->asyncStatus = PGASYNC_COPY_IN;
|
conn->asyncStatus = PGASYNC_COPY_IN;
|
||||||
break;
|
break;
|
||||||
case 'H': /* Start Copy Out */
|
case 'H': /* Start Copy Out */
|
||||||
if (pqGetc(&conn->copy_is_binary, conn))
|
if (getCopyStart(conn, PGRES_COPY_OUT))
|
||||||
return;
|
return;
|
||||||
/* XXX we currently ignore the rest of the message */
|
|
||||||
conn->inCursor = conn->inStart + 5 + msgLength;
|
|
||||||
conn->asyncStatus = PGASYNC_COPY_OUT;
|
conn->asyncStatus = PGASYNC_COPY_OUT;
|
||||||
conn->copy_already_done = 0;
|
conn->copy_already_done = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -398,6 +401,9 @@ getRowDescriptions(PGconn *conn)
|
||||||
MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc));
|
MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* result->binary is true only if ALL columns are binary */
|
||||||
|
result->binary = (nfields > 0) ? 1 : 0;
|
||||||
|
|
||||||
/* get type info */
|
/* get type info */
|
||||||
for (i = 0; i < nfields; i++)
|
for (i = 0; i < nfields; i++)
|
||||||
{
|
{
|
||||||
|
@ -430,10 +436,15 @@ getRowDescriptions(PGconn *conn)
|
||||||
|
|
||||||
result->attDescs[i].name = pqResultStrdup(result,
|
result->attDescs[i].name = pqResultStrdup(result,
|
||||||
conn->workBuffer.data);
|
conn->workBuffer.data);
|
||||||
|
result->attDescs[i].tableid = tableid;
|
||||||
|
result->attDescs[i].columnid = columnid;
|
||||||
|
result->attDescs[i].format = format;
|
||||||
result->attDescs[i].typid = typid;
|
result->attDescs[i].typid = typid;
|
||||||
result->attDescs[i].typlen = typlen;
|
result->attDescs[i].typlen = typlen;
|
||||||
result->attDescs[i].atttypmod = atttypmod;
|
result->attDescs[i].atttypmod = atttypmod;
|
||||||
/* XXX todo: save tableid/columnid, format too */
|
|
||||||
|
if (format != 1)
|
||||||
|
result->binary = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Success! */
|
/* Success! */
|
||||||
|
@ -503,7 +514,9 @@ getAnotherTuple(PGconn *conn, int msgLength)
|
||||||
vlen = 0;
|
vlen = 0;
|
||||||
if (tup[i].value == NULL)
|
if (tup[i].value == NULL)
|
||||||
{
|
{
|
||||||
tup[i].value = (char *) pqResultAlloc(result, vlen + 1, false);
|
bool isbinary = (result->attDescs[i].format != 0);
|
||||||
|
|
||||||
|
tup[i].value = (char *) pqResultAlloc(result, vlen + 1, isbinary);
|
||||||
if (tup[i].value == NULL)
|
if (tup[i].value == NULL)
|
||||||
goto outOfMemory;
|
goto outOfMemory;
|
||||||
}
|
}
|
||||||
|
@ -553,6 +566,7 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
PQExpBufferData workBuf;
|
PQExpBufferData workBuf;
|
||||||
char id;
|
char id;
|
||||||
|
const char *val;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make a PGresult to hold the accumulated fields. We temporarily
|
* Make a PGresult to hold the accumulated fields. We temporarily
|
||||||
|
@ -580,68 +594,63 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
|
||||||
break; /* terminator found */
|
break; /* terminator found */
|
||||||
if (pqGets(&workBuf, conn))
|
if (pqGets(&workBuf, conn))
|
||||||
goto fail;
|
goto fail;
|
||||||
switch (id)
|
pqSaveMessageField(res, id, workBuf.data);
|
||||||
{
|
|
||||||
case 'S':
|
|
||||||
res->errSeverity = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
res->errCode = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
res->errPrimary = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
res->errDetail = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
case 'H':
|
|
||||||
res->errHint = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
res->errPosition = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
case 'W':
|
|
||||||
res->errContext = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
res->errFilename = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
res->errLineno = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
res->errFuncname = pqResultStrdup(res, workBuf.data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* silently ignore any other field type */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now build the "overall" error message for PQresultErrorMessage.
|
* Now build the "overall" error message for PQresultErrorMessage.
|
||||||
*
|
|
||||||
* XXX this should be configurable somehow.
|
|
||||||
*/
|
*/
|
||||||
resetPQExpBuffer(&workBuf);
|
resetPQExpBuffer(&workBuf);
|
||||||
if (res->errSeverity)
|
val = PQresultErrorField(res, 'S'); /* Severity */
|
||||||
appendPQExpBuffer(&workBuf, "%s: ", res->errSeverity);
|
if (val)
|
||||||
if (res->errPrimary)
|
appendPQExpBuffer(&workBuf, "%s: ", val);
|
||||||
appendPQExpBufferStr(&workBuf, res->errPrimary);
|
if (conn->verbosity == PQERRORS_VERBOSE)
|
||||||
/* translator: %s represents a digit string */
|
{
|
||||||
if (res->errPosition)
|
val = PQresultErrorField(res, 'C'); /* SQLSTATE Code */
|
||||||
appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
|
if (val)
|
||||||
res->errPosition);
|
appendPQExpBuffer(&workBuf, "%s: ", val);
|
||||||
|
}
|
||||||
|
val = PQresultErrorField(res, 'M'); /* Primary message */
|
||||||
|
if (val)
|
||||||
|
appendPQExpBufferStr(&workBuf, val);
|
||||||
|
val = PQresultErrorField(res, 'P'); /* Position */
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
/* translator: %s represents a digit string */
|
||||||
|
appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"), val);
|
||||||
|
}
|
||||||
appendPQExpBufferChar(&workBuf, '\n');
|
appendPQExpBufferChar(&workBuf, '\n');
|
||||||
if (res->errDetail)
|
if (conn->verbosity != PQERRORS_TERSE)
|
||||||
appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL: %s\n"),
|
{
|
||||||
res->errDetail);
|
val = PQresultErrorField(res, 'D'); /* Detail */
|
||||||
if (res->errHint)
|
if (val)
|
||||||
appendPQExpBuffer(&workBuf, libpq_gettext("HINT: %s\n"),
|
appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL: %s\n"), val);
|
||||||
res->errHint);
|
val = PQresultErrorField(res, 'H'); /* Hint */
|
||||||
if (res->errContext)
|
if (val)
|
||||||
appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT: %s\n"),
|
appendPQExpBuffer(&workBuf, libpq_gettext("HINT: %s\n"), val);
|
||||||
res->errContext);
|
val = PQresultErrorField(res, 'W'); /* Where */
|
||||||
|
if (val)
|
||||||
|
appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT: %s\n"), val);
|
||||||
|
}
|
||||||
|
if (conn->verbosity == PQERRORS_VERBOSE)
|
||||||
|
{
|
||||||
|
const char *valf;
|
||||||
|
const char *vall;
|
||||||
|
|
||||||
|
valf = PQresultErrorField(res, 'F'); /* File */
|
||||||
|
vall = PQresultErrorField(res, 'L'); /* Line */
|
||||||
|
val = PQresultErrorField(res, 'R'); /* Routine */
|
||||||
|
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.
|
* Either save error as current async result, or just emit the notice.
|
||||||
|
@ -656,7 +665,9 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PGDONOTICE(conn, workBuf.data);
|
/* We can cheat a little here and not copy the message. */
|
||||||
|
res->errMsg = workBuf.data;
|
||||||
|
(*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,35 +721,216 @@ static int
|
||||||
getNotify(PGconn *conn)
|
getNotify(PGconn *conn)
|
||||||
{
|
{
|
||||||
int be_pid;
|
int be_pid;
|
||||||
|
char *svname;
|
||||||
|
int nmlen;
|
||||||
|
int extralen;
|
||||||
PGnotify *newNotify;
|
PGnotify *newNotify;
|
||||||
|
|
||||||
if (pqGetInt(&be_pid, 4, conn))
|
if (pqGetInt(&be_pid, 4, conn))
|
||||||
return EOF;
|
return EOF;
|
||||||
if (pqGets(&conn->workBuffer, conn))
|
if (pqGets(&conn->workBuffer, conn))
|
||||||
return EOF;
|
return EOF;
|
||||||
|
/* must save name while getting extra string */
|
||||||
|
svname = strdup(conn->workBuffer.data);
|
||||||
|
if (!svname)
|
||||||
|
return EOF;
|
||||||
|
if (pqGets(&conn->workBuffer, conn))
|
||||||
|
{
|
||||||
|
free(svname);
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store the relation name right after the PQnotify structure so it
|
* Store the strings right after the PQnotify structure so it
|
||||||
* can all be freed at once. We don't use NAMEDATALEN because we
|
* can all be freed at once. We don't use NAMEDATALEN because we
|
||||||
* don't want to tie this interface to a specific server name length.
|
* don't want to tie this interface to a specific server name length.
|
||||||
*/
|
*/
|
||||||
newNotify = (PGnotify *) malloc(sizeof(PGnotify) +
|
nmlen = strlen(svname);
|
||||||
strlen(conn->workBuffer.data) +1);
|
extralen = strlen(conn->workBuffer.data);
|
||||||
|
newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + extralen + 2);
|
||||||
if (newNotify)
|
if (newNotify)
|
||||||
{
|
{
|
||||||
newNotify->relname = (char *) newNotify + sizeof(PGnotify);
|
newNotify->relname = (char *) newNotify + sizeof(PGnotify);
|
||||||
strcpy(newNotify->relname, conn->workBuffer.data);
|
strcpy(newNotify->relname, svname);
|
||||||
|
newNotify->extra = newNotify->relname + nmlen + 1;
|
||||||
|
strcpy(newNotify->extra, conn->workBuffer.data);
|
||||||
newNotify->be_pid = be_pid;
|
newNotify->be_pid = be_pid;
|
||||||
DLAddTail(conn->notifyList, DLNewElem(newNotify));
|
DLAddTail(conn->notifyList, DLNewElem(newNotify));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Swallow extra string (not presently used) */
|
free(svname);
|
||||||
if (pqGets(&conn->workBuffer, conn))
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getCopyStart - process CopyInResponse or CopyOutResponse message
|
||||||
|
*
|
||||||
|
* parseInput already read the message type and length.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
getCopyStart(PGconn *conn, ExecStatusType copytype)
|
||||||
|
{
|
||||||
|
PGresult *result;
|
||||||
|
int nfields;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
result = PQmakeEmptyPGresult(conn, copytype);
|
||||||
|
|
||||||
|
if (pqGetc(&conn->copy_is_binary, conn))
|
||||||
|
{
|
||||||
|
PQclear(result);
|
||||||
return EOF;
|
return EOF;
|
||||||
|
}
|
||||||
|
result->binary = conn->copy_is_binary;
|
||||||
|
/* the next two bytes are the number of fields */
|
||||||
|
if (pqGetInt(&(result->numAttributes), 2, conn))
|
||||||
|
{
|
||||||
|
PQclear(result);
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
nfields = result->numAttributes;
|
||||||
|
|
||||||
|
/* allocate space for the attribute descriptors */
|
||||||
|
if (nfields > 0)
|
||||||
|
{
|
||||||
|
result->attDescs = (PGresAttDesc *)
|
||||||
|
pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE);
|
||||||
|
MemSet((char *) result->attDescs, 0, nfields * sizeof(PGresAttDesc));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nfields; i++)
|
||||||
|
{
|
||||||
|
int format;
|
||||||
|
|
||||||
|
if (pqGetInt(&format, 2, conn))
|
||||||
|
{
|
||||||
|
PQclear(result);
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since pqGetInt treats 2-byte integers as unsigned, we need to
|
||||||
|
* coerce these results to signed form.
|
||||||
|
*/
|
||||||
|
format = (int) ((int16) format);
|
||||||
|
|
||||||
|
result->attDescs[i].format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success! */
|
||||||
|
conn->result = result;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getReadyForQuery - process ReadyForQuery message
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
getReadyForQuery(PGconn *conn)
|
||||||
|
{
|
||||||
|
char xact_status;
|
||||||
|
|
||||||
|
if (pqGetc(&xact_status, conn))
|
||||||
|
return EOF;
|
||||||
|
switch (xact_status)
|
||||||
|
{
|
||||||
|
case 'I':
|
||||||
|
conn->xactStatus = PQTRANS_IDLE;
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
conn->xactStatus = PQTRANS_INTRANS;
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
conn->xactStatus = PQTRANS_INERROR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
conn->xactStatus = PQTRANS_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PQgetCopyData - read a row of data from the backend during COPY OUT
|
||||||
|
*
|
||||||
|
* If successful, sets *buffer to point to a malloc'd row of data, and
|
||||||
|
* returns row length (always > 0) as result.
|
||||||
|
* Returns 0 if no row available yet (only possible if async is true),
|
||||||
|
* -1 if end of copy (consult PQgetResult), or -2 if error (consult
|
||||||
|
* PQerrorMessage).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
pqGetCopyData3(PGconn *conn, char **buffer, int async)
|
||||||
|
{
|
||||||
|
char id;
|
||||||
|
int msgLength;
|
||||||
|
int avail;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Do we have 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.
|
||||||
|
*/
|
||||||
|
conn->inCursor = conn->inStart;
|
||||||
|
if (pqGetc(&id, conn))
|
||||||
|
goto nodata;
|
||||||
|
if (pqGetInt(&msgLength, 4, conn))
|
||||||
|
goto nodata;
|
||||||
|
avail = conn->inEnd - conn->inCursor;
|
||||||
|
if (avail < msgLength - 4)
|
||||||
|
goto nodata;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it's anything except Copy Data, exit COPY_OUT mode and let
|
||||||
|
* caller read status with PQgetResult(). The normal case is that
|
||||||
|
* it's Copy Done, but we let parseInput read that.
|
||||||
|
*/
|
||||||
|
if (id != 'd')
|
||||||
|
{
|
||||||
|
conn->asyncStatus = PGASYNC_BUSY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PQgetline - gets a newline-terminated string from the backend.
|
* PQgetline - gets a newline-terminated string from the backend.
|
||||||
|
@ -1108,7 +1300,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid,
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
case 'Z': /* backend is ready for new query */
|
case 'Z': /* backend is ready for new query */
|
||||||
if (pqGetc(&conn->xact_status, conn))
|
if (getReadyForQuery(conn))
|
||||||
continue;
|
continue;
|
||||||
/* consume the message and exit */
|
/* consume the message and exit */
|
||||||
conn->inStart += 5 + msgLength;
|
conn->inStart += 5 + msgLength;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: libpq-fe.h,v 1.93 2003/06/08 17:43:00 tgl Exp $
|
* $Id: libpq-fe.h,v 1.94 2003/06/21 21:51:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -88,6 +88,22 @@ typedef enum
|
||||||
PGRES_FATAL_ERROR /* query failed */
|
PGRES_FATAL_ERROR /* query failed */
|
||||||
} ExecStatusType;
|
} ExecStatusType;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PQTRANS_IDLE, /* connection idle */
|
||||||
|
PQTRANS_ACTIVE, /* command in progress */
|
||||||
|
PQTRANS_INTRANS, /* idle, within transaction block */
|
||||||
|
PQTRANS_INERROR, /* idle, within failed transaction */
|
||||||
|
PQTRANS_UNKNOWN /* cannot determine status */
|
||||||
|
} PGTransactionStatusType;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PQERRORS_TERSE, /* single-line error messages */
|
||||||
|
PQERRORS_DEFAULT, /* recommended style */
|
||||||
|
PQERRORS_VERBOSE /* all the facts, ma'am */
|
||||||
|
} PGVerbosity;
|
||||||
|
|
||||||
/* PGconn encapsulates a connection to the backend.
|
/* PGconn encapsulates a connection to the backend.
|
||||||
* The contents of this struct are not supposed to be known to applications.
|
* The contents of this struct are not supposed to be known to applications.
|
||||||
*/
|
*/
|
||||||
|
@ -108,12 +124,13 @@ typedef struct pg_result PGresult;
|
||||||
*/
|
*/
|
||||||
typedef struct pgNotify
|
typedef struct pgNotify
|
||||||
{
|
{
|
||||||
char *relname; /* name of relation containing data */
|
char *relname; /* notification condition name */
|
||||||
int be_pid; /* process id of backend */
|
int be_pid; /* process ID of server process */
|
||||||
|
char *extra; /* notification parameter */
|
||||||
} PGnotify;
|
} PGnotify;
|
||||||
|
|
||||||
/* PQnoticeProcessor is the function type for the notice-message callback.
|
/* Function types for notice-handling callbacks */
|
||||||
*/
|
typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res);
|
||||||
typedef void (*PQnoticeProcessor) (void *arg, const char *message);
|
typedef void (*PQnoticeProcessor) (void *arg, const char *message);
|
||||||
|
|
||||||
/* Print options for PQprint() */
|
/* Print options for PQprint() */
|
||||||
|
@ -227,6 +244,10 @@ extern char *PQport(const PGconn *conn);
|
||||||
extern char *PQtty(const PGconn *conn);
|
extern char *PQtty(const PGconn *conn);
|
||||||
extern char *PQoptions(const PGconn *conn);
|
extern char *PQoptions(const PGconn *conn);
|
||||||
extern ConnStatusType PQstatus(const PGconn *conn);
|
extern ConnStatusType PQstatus(const PGconn *conn);
|
||||||
|
extern PGTransactionStatusType PQtransactionStatus(const PGconn *conn);
|
||||||
|
extern const char *PQparameterStatus(const PGconn *conn,
|
||||||
|
const char *paramName);
|
||||||
|
extern int PQprotocolVersion(const PGconn *conn);
|
||||||
extern char *PQerrorMessage(const PGconn *conn);
|
extern char *PQerrorMessage(const PGconn *conn);
|
||||||
extern int PQsocket(const PGconn *conn);
|
extern int PQsocket(const PGconn *conn);
|
||||||
extern int PQbackendPID(const PGconn *conn);
|
extern int PQbackendPID(const PGconn *conn);
|
||||||
|
@ -238,42 +259,58 @@ extern int PQsetClientEncoding(PGconn *conn, const char *encoding);
|
||||||
extern SSL *PQgetssl(PGconn *conn);
|
extern SSL *PQgetssl(PGconn *conn);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Set verbosity for PQerrorMessage and PQresultErrorMessage */
|
||||||
|
extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
|
||||||
|
|
||||||
/* Enable/disable tracing */
|
/* Enable/disable tracing */
|
||||||
extern void PQtrace(PGconn *conn, FILE *debug_port);
|
extern void PQtrace(PGconn *conn, FILE *debug_port);
|
||||||
extern void PQuntrace(PGconn *conn);
|
extern void PQuntrace(PGconn *conn);
|
||||||
|
|
||||||
/* Override default notice processor */
|
/* Override default notice handling routines */
|
||||||
|
extern PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn,
|
||||||
|
PQnoticeReceiver proc,
|
||||||
|
void *arg);
|
||||||
extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
|
extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
|
||||||
PQnoticeProcessor proc,
|
PQnoticeProcessor proc,
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
/* === in fe-exec.c === */
|
/* === in fe-exec.c === */
|
||||||
|
|
||||||
/* Quoting strings before inclusion in queries. */
|
|
||||||
extern size_t PQescapeString(char *to, const char *from, size_t length);
|
|
||||||
extern unsigned char *PQescapeBytea(const unsigned char *bintext, size_t binlen,
|
|
||||||
size_t *bytealen);
|
|
||||||
extern unsigned char *PQunescapeBytea(const unsigned char *strtext,
|
|
||||||
size_t *retbuflen);
|
|
||||||
extern void PQfreemem(void *ptr);
|
|
||||||
|
|
||||||
|
|
||||||
/* Simple synchronous query */
|
/* Simple synchronous query */
|
||||||
extern PGresult *PQexec(PGconn *conn, const char *query);
|
extern PGresult *PQexec(PGconn *conn, const char *query);
|
||||||
extern PGnotify *PQnotifies(PGconn *conn);
|
extern PGresult *PQexecParams(PGconn *conn,
|
||||||
/* Exists for backward compatibility. bjm 2003-03-24 */
|
const char *command,
|
||||||
#define PQfreeNotify(ptr) PQfreemem(ptr)
|
int nParams,
|
||||||
|
const Oid *paramTypes,
|
||||||
|
const char * const *paramValues,
|
||||||
|
const int *paramLengths,
|
||||||
|
const int *paramFormats,
|
||||||
|
int resultFormat);
|
||||||
|
|
||||||
/* Interface for multiple-result or asynchronous queries */
|
/* Interface for multiple-result or asynchronous queries */
|
||||||
extern int PQsendQuery(PGconn *conn, const char *query);
|
extern int PQsendQuery(PGconn *conn, const char *query);
|
||||||
|
extern int PQsendQueryParams(PGconn *conn,
|
||||||
|
const char *command,
|
||||||
|
int nParams,
|
||||||
|
const Oid *paramTypes,
|
||||||
|
const char * const *paramValues,
|
||||||
|
const int *paramLengths,
|
||||||
|
const int *paramFormats,
|
||||||
|
int resultFormat);
|
||||||
extern PGresult *PQgetResult(PGconn *conn);
|
extern PGresult *PQgetResult(PGconn *conn);
|
||||||
|
|
||||||
/* Routines for managing an asynchronous query */
|
/* Routines for managing an asynchronous query */
|
||||||
extern int PQisBusy(PGconn *conn);
|
extern int PQisBusy(PGconn *conn);
|
||||||
extern int PQconsumeInput(PGconn *conn);
|
extern int PQconsumeInput(PGconn *conn);
|
||||||
|
|
||||||
|
/* LISTEN/NOTIFY support */
|
||||||
|
extern PGnotify *PQnotifies(PGconn *conn);
|
||||||
|
|
||||||
/* Routines for copy in/out */
|
/* Routines for copy in/out */
|
||||||
|
extern int PQputCopyData(PGconn *conn, const char *buffer, int nbytes);
|
||||||
|
extern int PQputCopyEnd(PGconn *conn, const char *errormsg);
|
||||||
|
extern int PQgetCopyData(PGconn *conn, char **buffer, int async);
|
||||||
|
/* Deprecated routines for copy in/out */
|
||||||
extern int PQgetline(PGconn *conn, char *string, int length);
|
extern int PQgetline(PGconn *conn, char *string, int length);
|
||||||
extern int PQputline(PGconn *conn, const char *string);
|
extern int PQputline(PGconn *conn, const char *string);
|
||||||
extern int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
|
extern int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
|
||||||
|
@ -303,11 +340,15 @@ extern PGresult *PQfn(PGconn *conn,
|
||||||
extern ExecStatusType PQresultStatus(const PGresult *res);
|
extern ExecStatusType PQresultStatus(const PGresult *res);
|
||||||
extern char *PQresStatus(ExecStatusType status);
|
extern char *PQresStatus(ExecStatusType status);
|
||||||
extern char *PQresultErrorMessage(const PGresult *res);
|
extern char *PQresultErrorMessage(const PGresult *res);
|
||||||
|
extern char *PQresultErrorField(const PGresult *res, int fieldcode);
|
||||||
extern int PQntuples(const PGresult *res);
|
extern int PQntuples(const PGresult *res);
|
||||||
extern int PQnfields(const PGresult *res);
|
extern int PQnfields(const PGresult *res);
|
||||||
extern int PQbinaryTuples(const PGresult *res);
|
extern int PQbinaryTuples(const PGresult *res);
|
||||||
extern char *PQfname(const PGresult *res, int field_num);
|
extern char *PQfname(const PGresult *res, int field_num);
|
||||||
extern int PQfnumber(const PGresult *res, const char *field_name);
|
extern int PQfnumber(const PGresult *res, const char *field_name);
|
||||||
|
extern Oid PQftable(const PGresult *res, int field_num);
|
||||||
|
extern int PQftablecol(const PGresult *res, int field_num);
|
||||||
|
extern int PQfformat(const PGresult *res, int field_num);
|
||||||
extern Oid PQftype(const PGresult *res, int field_num);
|
extern Oid PQftype(const PGresult *res, int field_num);
|
||||||
extern int PQfsize(const PGresult *res, int field_num);
|
extern int PQfsize(const PGresult *res, int field_num);
|
||||||
extern int PQfmod(const PGresult *res, int field_num);
|
extern int PQfmod(const PGresult *res, int field_num);
|
||||||
|
@ -322,6 +363,12 @@ extern int PQgetisnull(const PGresult *res, int tup_num, int field_num);
|
||||||
/* Delete a PGresult */
|
/* Delete a PGresult */
|
||||||
extern void PQclear(PGresult *res);
|
extern void PQclear(PGresult *res);
|
||||||
|
|
||||||
|
/* For freeing other alloc'd results, such as PGnotify structs */
|
||||||
|
extern void PQfreemem(void *ptr);
|
||||||
|
|
||||||
|
/* Exists for backward compatibility. bjm 2003-03-24 */
|
||||||
|
#define PQfreeNotify(ptr) PQfreemem(ptr)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make an empty PGresult with given status (some apps find this
|
* Make an empty PGresult with given status (some apps find this
|
||||||
* useful). If conn is not NULL and status indicates an error, the
|
* useful). If conn is not NULL and status indicates an error, the
|
||||||
|
@ -329,26 +376,33 @@ extern void PQclear(PGresult *res);
|
||||||
*/
|
*/
|
||||||
extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
|
extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
|
||||||
|
|
||||||
|
|
||||||
|
/* Quoting strings before inclusion in queries. */
|
||||||
|
extern size_t PQescapeString(char *to, const char *from, size_t length);
|
||||||
|
extern unsigned char *PQescapeBytea(const unsigned char *bintext, size_t binlen,
|
||||||
|
size_t *bytealen);
|
||||||
|
extern unsigned char *PQunescapeBytea(const unsigned char *strtext,
|
||||||
|
size_t *retbuflen);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* === in fe-print.c === */
|
/* === in fe-print.c === */
|
||||||
|
|
||||||
extern void
|
extern void PQprint(FILE *fout, /* output stream */
|
||||||
PQprint(FILE *fout, /* output stream */
|
const PGresult *res,
|
||||||
const PGresult *res,
|
const PQprintOpt *ps); /* option structure */
|
||||||
const PQprintOpt *ps); /* option structure */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* really old printing routines
|
* really old printing routines
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void PQdisplayTuples(const PGresult *res,
|
||||||
PQdisplayTuples(const PGresult *res,
|
|
||||||
FILE *fp, /* where to send the output */
|
FILE *fp, /* where to send the output */
|
||||||
int fillAlign, /* pad the fields with spaces */
|
int fillAlign, /* pad the fields with spaces */
|
||||||
const char *fieldSep, /* field separator */
|
const char *fieldSep, /* field separator */
|
||||||
int printHeader, /* display headers? */
|
int printHeader, /* display headers? */
|
||||||
int quiet);
|
int quiet);
|
||||||
|
|
||||||
extern void
|
extern void PQprintTuples(const PGresult *res,
|
||||||
PQprintTuples(const PGresult *res,
|
|
||||||
FILE *fout, /* output stream */
|
FILE *fout, /* output stream */
|
||||||
int printAttName, /* print attribute names */
|
int printAttName, /* print attribute names */
|
||||||
int terseOutput, /* delimiter bars */
|
int terseOutput, /* delimiter bars */
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: libpq-int.h,v 1.74 2003/06/14 17:49:54 momjian Exp $
|
* $Id: libpq-int.h,v 1.75 2003/06/21 21:51:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -20,6 +20,9 @@
|
||||||
#ifndef LIBPQ_INT_H
|
#ifndef LIBPQ_INT_H
|
||||||
#define LIBPQ_INT_H
|
#define LIBPQ_INT_H
|
||||||
|
|
||||||
|
/* We assume libpq-fe.h has already been included. */
|
||||||
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
|
@ -28,13 +31,10 @@
|
||||||
|
|
||||||
|
|
||||||
#if defined(WIN32) && (!defined(ssize_t))
|
#if defined(WIN32) && (!defined(ssize_t))
|
||||||
typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
|
typedef int ssize_t; /* ssize_t doesn't exist in VC (at least
|
||||||
* not VC6) */
|
* not VC6) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* We assume libpq-fe.h has already been included. */
|
|
||||||
#include "postgres_fe.h"
|
|
||||||
|
|
||||||
/* include stuff common to fe and be */
|
/* include stuff common to fe and be */
|
||||||
#include "getaddrinfo.h"
|
#include "getaddrinfo.h"
|
||||||
#include "libpq/pqcomm.h"
|
#include "libpq/pqcomm.h"
|
||||||
|
@ -78,7 +78,10 @@ union pgresult_data
|
||||||
|
|
||||||
typedef struct pgresAttDesc
|
typedef struct pgresAttDesc
|
||||||
{
|
{
|
||||||
char *name; /* type name */
|
char *name; /* column name */
|
||||||
|
Oid tableid; /* source table, if known */
|
||||||
|
int columnid; /* source column, if known */
|
||||||
|
int format; /* format code for value (text/binary) */
|
||||||
Oid typid; /* type id */
|
Oid typid; /* type id */
|
||||||
int typlen; /* type size */
|
int typlen; /* type size */
|
||||||
int atttypmod; /* type-specific modifier info */
|
int atttypmod; /* type-specific modifier info */
|
||||||
|
@ -91,7 +94,7 @@ typedef struct pgresAttDesc
|
||||||
*
|
*
|
||||||
* The value pointer always points to a null-terminated area; we add a
|
* The value pointer always points to a null-terminated area; we add a
|
||||||
* null (zero) byte after whatever the backend sends us. This is only
|
* null (zero) byte after whatever the backend sends us. This is only
|
||||||
* particularly useful for text tuples ... with a binary value, the
|
* particularly useful for text values ... with a binary value, the
|
||||||
* value might have embedded nulls, so the application can't use C string
|
* value might have embedded nulls, so the application can't use C string
|
||||||
* operators on it. But we add a null anyway for consistency.
|
* operators on it. But we add a null anyway for consistency.
|
||||||
* Note that the value itself does not contain a length word.
|
* Note that the value itself does not contain a length word.
|
||||||
|
@ -111,6 +114,23 @@ typedef struct pgresAttValue
|
||||||
* byte */
|
* byte */
|
||||||
} PGresAttValue;
|
} PGresAttValue;
|
||||||
|
|
||||||
|
/* Typedef for message-field list entries */
|
||||||
|
typedef struct pgMessageField
|
||||||
|
{
|
||||||
|
struct pgMessageField *next; /* list link */
|
||||||
|
char code; /* field code */
|
||||||
|
char contents[1]; /* field value (VARIABLE LENGTH) */
|
||||||
|
} PGMessageField;
|
||||||
|
|
||||||
|
/* Fields needed for notice handling */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
PQnoticeReceiver noticeRec; /* notice message receiver */
|
||||||
|
void *noticeRecArg;
|
||||||
|
PQnoticeProcessor noticeProc; /* notice message processor */
|
||||||
|
void *noticeProcArg;
|
||||||
|
} PGNoticeHooks;
|
||||||
|
|
||||||
struct pg_result
|
struct pg_result
|
||||||
{
|
{
|
||||||
int ntups;
|
int ntups;
|
||||||
|
@ -118,10 +138,10 @@ struct pg_result
|
||||||
PGresAttDesc *attDescs;
|
PGresAttDesc *attDescs;
|
||||||
PGresAttValue **tuples; /* each PGresTuple is an array of
|
PGresAttValue **tuples; /* each PGresTuple is an array of
|
||||||
* PGresAttValue's */
|
* PGresAttValue's */
|
||||||
int tupArrSize; /* size of tuples array allocated */
|
int tupArrSize; /* allocated size of tuples array */
|
||||||
ExecStatusType resultStatus;
|
ExecStatusType resultStatus;
|
||||||
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the
|
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the
|
||||||
* last query */
|
* query */
|
||||||
int binary; /* binary tuple values if binary == 1,
|
int binary; /* binary tuple values if binary == 1,
|
||||||
* otherwise text */
|
* otherwise text */
|
||||||
|
|
||||||
|
@ -129,35 +149,23 @@ struct pg_result
|
||||||
* These fields are copied from the originating PGconn, so that
|
* These fields are copied from the originating PGconn, so that
|
||||||
* operations on the PGresult don't have to reference the PGconn.
|
* operations on the PGresult don't have to reference the PGconn.
|
||||||
*/
|
*/
|
||||||
PQnoticeProcessor noticeHook; /* notice/error message processor */
|
PGNoticeHooks noticeHooks;
|
||||||
void *noticeArg;
|
|
||||||
int client_encoding; /* encoding id */
|
int client_encoding; /* encoding id */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Error information (all NULL if not an error result). errMsg is the
|
* Error information (all NULL if not an error result). errMsg is the
|
||||||
* "overall" error message returned by PQresultErrorMessage. If we
|
* "overall" error message returned by PQresultErrorMessage. If we
|
||||||
* got a field-ized error from the server then the additional fields
|
* have per-field info then it is stored in a linked list.
|
||||||
* may be set.
|
|
||||||
*/
|
*/
|
||||||
char *errMsg; /* error message, or NULL if no error */
|
char *errMsg; /* error message, or NULL if no error */
|
||||||
|
PGMessageField *errFields; /* message broken into fields */
|
||||||
char *errSeverity; /* severity code */
|
|
||||||
char *errCode; /* SQLSTATE code */
|
|
||||||
char *errPrimary; /* primary message text */
|
|
||||||
char *errDetail; /* detail text */
|
|
||||||
char *errHint; /* hint text */
|
|
||||||
char *errPosition; /* cursor position */
|
|
||||||
char *errContext; /* location information */
|
|
||||||
char *errFilename; /* source-code file name */
|
|
||||||
char *errLineno; /* source-code line number */
|
|
||||||
char *errFuncname; /* source-code function name */
|
|
||||||
|
|
||||||
/* All NULL attributes in the query result point to this null string */
|
/* All NULL attributes in the query result point to this null string */
|
||||||
char null_field[1];
|
char null_field[1];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Space management information. Note that attDescs and errMsg, if
|
* Space management information. Note that attDescs and error stuff,
|
||||||
* not null, point into allocated blocks. But tuples points to a
|
* if not null, point into allocated blocks. But tuples points to a
|
||||||
* separately malloc'd block, so that we can realloc it.
|
* separately malloc'd block, so that we can realloc it.
|
||||||
*/
|
*/
|
||||||
PGresult_data *curBlock; /* most recently allocated block */
|
PGresult_data *curBlock; /* most recently allocated block */
|
||||||
|
@ -245,18 +253,18 @@ struct pg_conn
|
||||||
/* Optional file to write trace info to */
|
/* Optional file to write trace info to */
|
||||||
FILE *Pfdebug;
|
FILE *Pfdebug;
|
||||||
|
|
||||||
/* Callback procedure for notice/error message processing */
|
/* Callback procedures for notice message processing */
|
||||||
PQnoticeProcessor noticeHook;
|
PGNoticeHooks noticeHooks;
|
||||||
void *noticeArg;
|
|
||||||
|
|
||||||
/* Status indicators */
|
/* Status indicators */
|
||||||
ConnStatusType status;
|
ConnStatusType status;
|
||||||
PGAsyncStatusType asyncStatus;
|
PGAsyncStatusType asyncStatus;
|
||||||
char xact_status; /* status flag from latest ReadyForQuery */
|
PGTransactionStatusType xactStatus;
|
||||||
char copy_is_binary; /* 1 = copy binary, 0 = copy text */
|
/* note: xactStatus never changes to ACTIVE */
|
||||||
int copy_already_done; /* # bytes already returned in COPY OUT */
|
|
||||||
int nonblocking; /* whether this connection is using a
|
int nonblocking; /* whether this connection is using a
|
||||||
* blocking socket to the backend or not */
|
* blocking socket to the backend or not */
|
||||||
|
char copy_is_binary; /* 1 = copy binary, 0 = copy text */
|
||||||
|
int copy_already_done; /* # bytes already returned in COPY OUT */
|
||||||
Dllist *notifyList; /* Notify msgs not yet handed to
|
Dllist *notifyList; /* Notify msgs not yet handed to
|
||||||
* application */
|
* application */
|
||||||
|
|
||||||
|
@ -281,6 +289,7 @@ struct pg_conn
|
||||||
char cryptSalt[2]; /* password salt received from backend */
|
char cryptSalt[2]; /* password salt received from backend */
|
||||||
pgParameterStatus *pstatus; /* ParameterStatus data */
|
pgParameterStatus *pstatus; /* ParameterStatus data */
|
||||||
int client_encoding; /* encoding id */
|
int client_encoding; /* encoding id */
|
||||||
|
PGVerbosity verbosity; /* error/notice message verbosity */
|
||||||
PGlobjfuncs *lobjfuncs; /* private state for large-object access
|
PGlobjfuncs *lobjfuncs; /* private state for large-object access
|
||||||
* fns */
|
* fns */
|
||||||
|
|
||||||
|
@ -351,10 +360,12 @@ extern char *pqResultStrdup(PGresult *res, const char *str);
|
||||||
extern void pqClearAsyncResult(PGconn *conn);
|
extern void pqClearAsyncResult(PGconn *conn);
|
||||||
extern void pqSaveErrorResult(PGconn *conn);
|
extern void pqSaveErrorResult(PGconn *conn);
|
||||||
extern PGresult *pqPrepareAsyncResult(PGconn *conn);
|
extern PGresult *pqPrepareAsyncResult(PGconn *conn);
|
||||||
|
extern void pqInternalNotice(const PGNoticeHooks *hooks, const char *msgtext);
|
||||||
extern int pqAddTuple(PGresult *res, PGresAttValue *tup);
|
extern int pqAddTuple(PGresult *res, PGresAttValue *tup);
|
||||||
|
extern void pqSaveMessageField(PGresult *res, char code,
|
||||||
|
const char *value);
|
||||||
extern void pqSaveParameterStatus(PGconn *conn, const char *name,
|
extern void pqSaveParameterStatus(PGconn *conn, const char *name,
|
||||||
const char *value);
|
const char *value);
|
||||||
extern const char *pqGetParameterStatus(PGconn *conn, const char *name);
|
|
||||||
extern void pqHandleSendFailure(PGconn *conn);
|
extern void pqHandleSendFailure(PGconn *conn);
|
||||||
|
|
||||||
/* === in fe-protocol2.c === */
|
/* === in fe-protocol2.c === */
|
||||||
|
@ -364,6 +375,7 @@ extern PostgresPollingStatusType pqSetenvPoll(PGconn *conn);
|
||||||
extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen,
|
extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen,
|
||||||
const PQEnvironmentOption *options);
|
const PQEnvironmentOption *options);
|
||||||
extern void pqParseInput2(PGconn *conn);
|
extern void pqParseInput2(PGconn *conn);
|
||||||
|
extern int pqGetCopyData2(PGconn *conn, char **buffer, int async);
|
||||||
extern int pqGetline2(PGconn *conn, char *s, int maxlen);
|
extern int pqGetline2(PGconn *conn, char *s, int maxlen);
|
||||||
extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize);
|
extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize);
|
||||||
extern int pqEndcopy2(PGconn *conn);
|
extern int pqEndcopy2(PGconn *conn);
|
||||||
|
@ -378,6 +390,7 @@ extern char *pqBuildStartupPacket3(PGconn *conn, int *packetlen,
|
||||||
const PQEnvironmentOption *options);
|
const PQEnvironmentOption *options);
|
||||||
extern void pqParseInput3(PGconn *conn);
|
extern void pqParseInput3(PGconn *conn);
|
||||||
extern int pqGetErrorNotice3(PGconn *conn, bool isError);
|
extern int pqGetErrorNotice3(PGconn *conn, bool isError);
|
||||||
|
extern int pqGetCopyData3(PGconn *conn, char **buffer, int async);
|
||||||
extern int pqGetline3(PGconn *conn, char *s, int maxlen);
|
extern int pqGetline3(PGconn *conn, char *s, int maxlen);
|
||||||
extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize);
|
extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize);
|
||||||
extern int pqEndcopy3(PGconn *conn);
|
extern int pqEndcopy3(PGconn *conn);
|
||||||
|
@ -393,6 +406,7 @@ extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid,
|
||||||
* for Get, EOF merely means the buffer is exhausted, not that there is
|
* for Get, EOF merely means the buffer is exhausted, not that there is
|
||||||
* necessarily any error.
|
* necessarily any error.
|
||||||
*/
|
*/
|
||||||
|
extern int pqCheckOutBufferSpace(int bytes_needed, PGconn *conn);
|
||||||
extern int pqCheckInBufferSpace(int bytes_needed, PGconn *conn);
|
extern int pqCheckInBufferSpace(int bytes_needed, PGconn *conn);
|
||||||
extern int pqGetc(char *result, PGconn *conn);
|
extern int pqGetc(char *result, PGconn *conn);
|
||||||
extern int pqPutc(char c, PGconn *conn);
|
extern int pqPutc(char c, PGconn *conn);
|
||||||
|
@ -423,10 +437,10 @@ extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len);
|
||||||
|
|
||||||
/* Note: PGDONOTICE macro will work if applied to either PGconn or PGresult */
|
/* Note: PGDONOTICE macro will work if applied to either PGconn or PGresult */
|
||||||
#define PGDONOTICE(conn,message) \
|
#define PGDONOTICE(conn,message) \
|
||||||
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
pqInternalNotice(&(conn)->noticeHooks, (message))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this is so that we can check is a connection is non-blocking internally
|
* this is so that we can check if a connection is non-blocking internally
|
||||||
* without the overhead of a function call
|
* without the overhead of a function call
|
||||||
*/
|
*/
|
||||||
#define pqIsnonblocking(conn) ((conn)->nonblocking)
|
#define pqIsnonblocking(conn) ((conn)->nonblocking)
|
||||||
|
|
|
@ -97,4 +97,17 @@ EXPORTS
|
||||||
pg_utf_mblen @ 93
|
pg_utf_mblen @ 93
|
||||||
PQunescapeBytea @ 94
|
PQunescapeBytea @ 94
|
||||||
PQfreemem @ 95
|
PQfreemem @ 95
|
||||||
|
PQtransactionStatus @ 96
|
||||||
|
PQparameterStatus @ 97
|
||||||
|
PQprotocolVersion @ 98
|
||||||
|
PQsetErrorVerbosity @ 99
|
||||||
|
PQsetNoticeReceiver @ 100
|
||||||
|
PQexecParams @ 101
|
||||||
|
PQsendQueryParams @ 102
|
||||||
|
PQputCopyData @ 103
|
||||||
|
PQputCopyEnd @ 104
|
||||||
|
PQgetCopyData @ 105
|
||||||
|
PQresultErrorField @ 106
|
||||||
|
PQftable @ 107
|
||||||
|
PQftablecol @ 108
|
||||||
|
PQfformat @ 109
|
||||||
|
|
Loading…
Reference in New Issue