mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
libpq can now talk to either 3.0 or 2.0 protocol servers. It first tries
protocol 3, then falls back to 2 if postmaster rejects the startup packet with an old-format error message. A side benefit of the rewrite is that SSL-encrypted connections can now be made without blocking. (I think, anyway, but do not have a good way to test.)
This commit is contained in:
parent
152ce7a490
commit
6bdb7aa4db
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.7 2003/04/22 03:52:56 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.8 2003/06/08 17:42:59 tgl Exp $
|
||||||
*
|
*
|
||||||
* This file and the IPV6 implementation were initially provided by
|
* This file and the IPV6 implementation were initially provided by
|
||||||
* Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
|
* Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
|
||||||
@ -72,27 +72,29 @@ getaddrinfo2(const char *hostname, const char *servname,
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* freeaddrinfo2 - free IPv6 addrinfo structures
|
* freeaddrinfo2 - free addrinfo structures for IPv4, IPv6, or Unix
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
freeaddrinfo2(int hint_ai_family, struct addrinfo *ai)
|
freeaddrinfo2(struct addrinfo *ai)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_UNIX_SOCKETS
|
if (ai != NULL)
|
||||||
if (hint_ai_family == AF_UNIX)
|
|
||||||
{
|
{
|
||||||
struct addrinfo *p;
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
|
if (ai->ai_family == AF_UNIX)
|
||||||
while (ai != NULL)
|
|
||||||
{
|
{
|
||||||
p = ai;
|
while (ai != NULL)
|
||||||
ai = ai->ai_next;
|
{
|
||||||
free(p->ai_addr);
|
struct addrinfo *p = ai;
|
||||||
free(p);
|
|
||||||
|
ai = ai->ai_next;
|
||||||
|
free(p->ai_addr);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
|
||||||
#endif /* HAVE_UNIX_SOCKETS */
|
#endif /* HAVE_UNIX_SOCKETS */
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +30,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
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.154 2003/05/29 19:15:34 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.155 2003/06/08 17:43:00 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -242,8 +242,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
{
|
{
|
||||||
elog(LOG, "server socket failure: getaddrinfo2(): %s",
|
elog(LOG, "server socket failure: getaddrinfo2(): %s",
|
||||||
gai_strerror(ret));
|
gai_strerror(ret));
|
||||||
if (addrs != NULL)
|
freeaddrinfo2(addrs);
|
||||||
freeaddrinfo2(hint.ai_family, addrs);
|
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +250,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
{
|
{
|
||||||
elog(LOG, "server socket failure: socket(): %s",
|
elog(LOG, "server socket failure: socket(): %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
freeaddrinfo2(hint.ai_family, addrs);
|
freeaddrinfo2(addrs);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +261,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
{
|
{
|
||||||
elog(LOG, "server socket failure: setsockopt(SO_REUSEADDR): %s",
|
elog(LOG, "server socket failure: setsockopt(SO_REUSEADDR): %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
freeaddrinfo2(hint.ai_family, addrs);
|
freeaddrinfo2(addrs);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,7 +278,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
sock_path);
|
sock_path);
|
||||||
else
|
else
|
||||||
elog(LOG, "\tIf not, wait a few seconds and retry.");
|
elog(LOG, "\tIf not, wait a few seconds and retry.");
|
||||||
freeaddrinfo2(hint.ai_family, addrs);
|
freeaddrinfo2(addrs);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +287,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
{
|
{
|
||||||
if (Setup_AF_UNIX() != STATUS_OK)
|
if (Setup_AF_UNIX() != STATUS_OK)
|
||||||
{
|
{
|
||||||
freeaddrinfo2(hint.ai_family, addrs);
|
freeaddrinfo2(addrs);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,12 +307,12 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
{
|
{
|
||||||
elog(LOG, "server socket failure: listen(): %s",
|
elog(LOG, "server socket failure: listen(): %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
freeaddrinfo2(hint.ai_family, addrs);
|
freeaddrinfo2(addrs);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
*fdP = fd;
|
*fdP = fd;
|
||||||
freeaddrinfo2(hint.ai_family, addrs);
|
freeaddrinfo2(addrs);
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2003, PostgreSQL Global Development Group
|
* Copyright (c) 2003, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $Id: ip.h,v 1.3 2003/04/02 00:49:28 tgl Exp $
|
* $Id: ip.h,v 1.4 2003/06/08 17:43:00 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -19,7 +19,7 @@
|
|||||||
extern int getaddrinfo2(const char *hostname, const char *servname,
|
extern int getaddrinfo2(const char *hostname, const char *servname,
|
||||||
const struct addrinfo *hintp,
|
const struct addrinfo *hintp,
|
||||||
struct addrinfo **result);
|
struct addrinfo **result);
|
||||||
extern void freeaddrinfo2(int hint_ai_family, struct addrinfo *ai);
|
extern void freeaddrinfo2(struct addrinfo *ai);
|
||||||
|
|
||||||
extern char *SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt,
|
extern char *SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt,
|
||||||
int v4conv);
|
int v4conv);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 1994, Regents of the University of California
|
# Copyright (c) 1994, Regents of the University of California
|
||||||
#
|
#
|
||||||
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.79 2003/05/10 02:05:50 momjian Exp $
|
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.80 2003/06/08 17:43:00 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ SO_MINOR_VERSION= 1
|
|||||||
override CPPFLAGS := -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"'
|
override CPPFLAGS := -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"'
|
||||||
|
|
||||||
OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
|
OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
|
||||||
pqexpbuffer.o pqsignal.o fe-secure.o \
|
fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
|
||||||
dllist.o md5.o ip.o wchar.o encnames.o \
|
dllist.o md5.o ip.o wchar.o encnames.o \
|
||||||
$(filter crypt.o getaddrinfo.o inet_aton.o snprintf.o strerror.o path.o, $(LIBOBJS))
|
$(filter crypt.o getaddrinfo.o inet_aton.o snprintf.o strerror.o path.o, $(LIBOBJS))
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
|
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.78 2003/05/16 04:58:03 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.79 2003/06/08 17:43:00 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -559,7 +559,11 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
|
|||||||
default:
|
default:
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
ret = pqPacketSend(conn, 'p', crypt_pwd, strlen(crypt_pwd) + 1);
|
/* Packet has a message type as of protocol 3.0 */
|
||||||
|
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
|
||||||
|
ret = pqPacketSend(conn, 'p', crypt_pwd, strlen(crypt_pwd) + 1);
|
||||||
|
else
|
||||||
|
ret = pqPacketSend(conn, 0, crypt_pwd, strlen(crypt_pwd) + 1);
|
||||||
if (areq == AUTH_REQ_MD5)
|
if (areq == AUTH_REQ_MD5)
|
||||||
free(crypt_pwd);
|
free(crypt_pwd);
|
||||||
return ret;
|
return ret;
|
||||||
|
File diff suppressed because it is too large
Load Diff
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.91 2003/04/25 01:24:00 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.92 2003/06/08 17:43:00 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -58,8 +58,6 @@
|
|||||||
#include "pqsignal.h"
|
#include "pqsignal.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
|
|
||||||
#define DONOTICE(conn,message) \
|
|
||||||
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
|
||||||
|
|
||||||
static int pqPutMsgBytes(const void *buf, size_t len, PGconn *conn);
|
static int pqPutMsgBytes(const void *buf, size_t len, PGconn *conn);
|
||||||
static int pqSendSome(PGconn *conn, int len);
|
static int pqSendSome(PGconn *conn, int len);
|
||||||
@ -227,7 +225,7 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
|
|||||||
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\n"),
|
||||||
(unsigned long) bytes);
|
(unsigned long) bytes);
|
||||||
DONOTICE(conn, noticeBuf);
|
PGDONOTICE(conn, noticeBuf);
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +263,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
|
|||||||
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\n"),
|
||||||
(unsigned long) bytes);
|
(unsigned long) bytes);
|
||||||
DONOTICE(conn, noticeBuf);
|
PGDONOTICE(conn, noticeBuf);
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,38 +399,57 @@ pqCheckInBufferSpace(int bytes_needed, PGconn *conn)
|
|||||||
* msg_type is the message type byte, or 0 for a message without type byte
|
* msg_type is the message type byte, or 0 for a message without type byte
|
||||||
* (only startup messages have no type byte)
|
* (only startup messages have no type byte)
|
||||||
*
|
*
|
||||||
|
* force_len forces the message to have a length word; otherwise, we add
|
||||||
|
* a length word if protocol 3.
|
||||||
|
*
|
||||||
* Returns 0 on success, EOF on error
|
* Returns 0 on success, EOF on error
|
||||||
*
|
*
|
||||||
* The idea here is that we construct the message in conn->outBuffer,
|
* The idea here is that we construct the message in conn->outBuffer,
|
||||||
* beginning just past any data already in outBuffer (ie, at
|
* beginning just past any data already in outBuffer (ie, at
|
||||||
* outBuffer+outCount). We enlarge the buffer as needed to hold the message.
|
* outBuffer+outCount). We enlarge the buffer as needed to hold the message.
|
||||||
* When the message is complete, we fill in the length word and then advance
|
* When the message is complete, we fill in the length word (if needed) and
|
||||||
* outCount past the message, making it eligible to send. The state
|
* then advance outCount past the message, making it eligible to send.
|
||||||
* variable conn->outMsgStart points to the incomplete message's length word
|
*
|
||||||
* (it is either outCount or outCount+1 depending on whether there is a
|
* The state variable conn->outMsgStart points to the incomplete message's
|
||||||
* type byte). The state variable conn->outMsgEnd is the end of the data
|
* length word: it is either outCount or outCount+1 depending on whether
|
||||||
* collected so far.
|
* there is a type byte. If we are sending a message without length word
|
||||||
|
* (pre protocol 3.0 only), then outMsgStart is -1. The state variable
|
||||||
|
* conn->outMsgEnd is the end of the data collected so far.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
pqPutMsgStart(char msg_type, PGconn *conn)
|
pqPutMsgStart(char msg_type, bool force_len, PGconn *conn)
|
||||||
{
|
{
|
||||||
int lenPos;
|
int lenPos;
|
||||||
|
int endPos;
|
||||||
|
|
||||||
/* where the message length word will go */
|
/* allow room for message type byte */
|
||||||
if (msg_type)
|
if (msg_type)
|
||||||
lenPos = conn->outCount + 1;
|
endPos = conn->outCount + 1;
|
||||||
else
|
else
|
||||||
lenPos = conn->outCount;
|
endPos = conn->outCount;
|
||||||
/* make sure there is room for it */
|
|
||||||
if (pqCheckOutBufferSpace(lenPos + 4, conn))
|
/* 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;
|
return EOF;
|
||||||
/* okay, save the message type byte if any */
|
/* okay, save the message type byte if any */
|
||||||
if (msg_type)
|
if (msg_type)
|
||||||
conn->outBuffer[conn->outCount] = msg_type;
|
conn->outBuffer[conn->outCount] = msg_type;
|
||||||
/* set up the message pointers */
|
/* set up the message pointers */
|
||||||
conn->outMsgStart = lenPos;
|
conn->outMsgStart = lenPos;
|
||||||
conn->outMsgEnd = lenPos + 4;
|
conn->outMsgEnd = endPos;
|
||||||
/* length word will be filled in by pqPutMsgEnd */
|
/* length word, if needed, will be filled in by pqPutMsgEnd */
|
||||||
|
|
||||||
if (conn->Pfdebug)
|
if (conn->Pfdebug)
|
||||||
fprintf(conn->Pfdebug, "To backend> Msg %c\n",
|
fprintf(conn->Pfdebug, "To backend> Msg %c\n",
|
||||||
@ -472,14 +489,20 @@ pqPutMsgBytes(const void *buf, size_t len, PGconn *conn)
|
|||||||
int
|
int
|
||||||
pqPutMsgEnd(PGconn *conn)
|
pqPutMsgEnd(PGconn *conn)
|
||||||
{
|
{
|
||||||
uint32 msgLen = conn->outMsgEnd - conn->outMsgStart;
|
|
||||||
|
|
||||||
if (conn->Pfdebug)
|
if (conn->Pfdebug)
|
||||||
fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n",
|
fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n",
|
||||||
msgLen);
|
conn->outMsgEnd - conn->outCount);
|
||||||
|
|
||||||
msgLen = htonl(msgLen);
|
/* Fill in length word if needed */
|
||||||
memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4);
|
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;
|
conn->outCount = conn->outMsgEnd;
|
||||||
|
|
||||||
if (conn->outCount >= 8192)
|
if (conn->outCount >= 8192)
|
||||||
|
1239
src/interfaces/libpq/fe-protocol2.c
Normal file
1239
src/interfaces/libpq/fe-protocol2.c
Normal file
File diff suppressed because it is too large
Load Diff
1247
src/interfaces/libpq/fe-protocol3.c
Normal file
1247
src/interfaces/libpq/fe-protocol3.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-secure.c,v 1.22 2003/04/10 23:03:08 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-secure.c,v 1.23 2003/06/08 17:43:00 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The client *requires* a valid server certificate. Since
|
* The client *requires* a valid server certificate. Since
|
||||||
@ -132,7 +132,7 @@ static DH *tmp_dh_cb(SSL *s, int is_export, int keylength);
|
|||||||
static int client_cert_cb(SSL *, X509 **, EVP_PKEY **);
|
static int client_cert_cb(SSL *, X509 **, EVP_PKEY **);
|
||||||
static int initialize_SSL(PGconn *);
|
static int initialize_SSL(PGconn *);
|
||||||
static void destroy_SSL(void);
|
static void destroy_SSL(void);
|
||||||
static int open_client_SSL(PGconn *);
|
static PostgresPollingStatusType open_client_SSL(PGconn *);
|
||||||
static void close_SSL(PGconn *);
|
static void close_SSL(PGconn *);
|
||||||
static const char *SSLerrmessage(void);
|
static const char *SSLerrmessage(void);
|
||||||
#endif
|
#endif
|
||||||
@ -231,16 +231,30 @@ pqsecure_destroy(void)
|
|||||||
/*
|
/*
|
||||||
* Attempt to negotiate secure session.
|
* Attempt to negotiate secure session.
|
||||||
*/
|
*/
|
||||||
int
|
PostgresPollingStatusType
|
||||||
pqsecure_open_client(PGconn *conn)
|
pqsecure_open_client(PGconn *conn)
|
||||||
{
|
{
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
#ifdef USE_SSL
|
#ifdef USE_SSL
|
||||||
r = open_client_SSL(conn);
|
/* First time through? */
|
||||||
|
if (conn->ssl == NULL)
|
||||||
|
{
|
||||||
|
if (!(conn->ssl = SSL_new(SSL_context)) ||
|
||||||
|
!SSL_set_app_data(conn->ssl, conn) ||
|
||||||
|
!SSL_set_fd(conn->ssl, conn->sock))
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("could not establish SSL connection: %s\n"),
|
||||||
|
SSLerrmessage());
|
||||||
|
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
|
#endif
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -273,8 +287,15 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len)
|
|||||||
case SSL_ERROR_NONE:
|
case SSL_ERROR_NONE:
|
||||||
break;
|
break;
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
|
n = 0;
|
||||||
|
break;
|
||||||
case SSL_ERROR_WANT_WRITE:
|
case SSL_ERROR_WANT_WRITE:
|
||||||
/* XXX to support nonblock I/O, we should return 0 here */
|
/*
|
||||||
|
* 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;
|
goto rloop;
|
||||||
case SSL_ERROR_SYSCALL:
|
case SSL_ERROR_SYSCALL:
|
||||||
if (n == -1)
|
if (n == -1)
|
||||||
@ -322,16 +343,22 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
|
|||||||
#ifdef USE_SSL
|
#ifdef USE_SSL
|
||||||
if (conn->ssl)
|
if (conn->ssl)
|
||||||
{
|
{
|
||||||
wloop:
|
|
||||||
n = SSL_write(conn->ssl, ptr, len);
|
n = SSL_write(conn->ssl, ptr, len);
|
||||||
switch (SSL_get_error(conn->ssl, n))
|
switch (SSL_get_error(conn->ssl, n))
|
||||||
{
|
{
|
||||||
case SSL_ERROR_NONE:
|
case SSL_ERROR_NONE:
|
||||||
break;
|
break;
|
||||||
case SSL_ERROR_WANT_READ:
|
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:
|
case SSL_ERROR_WANT_WRITE:
|
||||||
/* XXX to support nonblock I/O, we should return 0 here */
|
n = 0;
|
||||||
goto wloop;
|
break;
|
||||||
case SSL_ERROR_SYSCALL:
|
case SSL_ERROR_SYSCALL:
|
||||||
if (n == -1)
|
if (n == -1)
|
||||||
printfPQExpBuffer(&conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
@ -802,23 +829,45 @@ destroy_SSL(void)
|
|||||||
/*
|
/*
|
||||||
* Attempt to negotiate SSL connection.
|
* Attempt to negotiate SSL connection.
|
||||||
*/
|
*/
|
||||||
static int
|
static PostgresPollingStatusType
|
||||||
open_client_SSL(PGconn *conn)
|
open_client_SSL(PGconn *conn)
|
||||||
{
|
{
|
||||||
#ifdef NOT_USED
|
|
||||||
int r;
|
int r;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!(conn->ssl = SSL_new(SSL_context)) ||
|
r = SSL_connect(conn->ssl);
|
||||||
!SSL_set_app_data(conn->ssl, conn) ||
|
if (r <= 0)
|
||||||
!SSL_set_fd(conn->ssl, conn->sock) ||
|
|
||||||
SSL_connect(conn->ssl) <= 0)
|
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(&conn->errorMessage,
|
switch (SSL_get_error(conn->ssl, r))
|
||||||
libpq_gettext("could not establish SSL connection: %s\n"),
|
{
|
||||||
SSLerrmessage());
|
case SSL_ERROR_WANT_READ:
|
||||||
close_SSL(conn);
|
return PGRES_POLLING_READING;
|
||||||
return -1;
|
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
return PGRES_POLLING_WRITING;
|
||||||
|
|
||||||
|
case SSL_ERROR_SYSCALL:
|
||||||
|
if (r == -1)
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("SSL SYSCALL error: %s\n"),
|
||||||
|
SOCK_STRERROR(SOCK_ERRNO));
|
||||||
|
else
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("SSL SYSCALL error: EOF detected\n"));
|
||||||
|
close_SSL(conn);
|
||||||
|
return PGRES_POLLING_FAILED;
|
||||||
|
|
||||||
|
case SSL_ERROR_SSL:
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("SSL error: %s\n"), SSLerrmessage());
|
||||||
|
close_SSL(conn);
|
||||||
|
return PGRES_POLLING_FAILED;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("Unknown SSL error code\n"));
|
||||||
|
close_SSL(conn);
|
||||||
|
return PGRES_POLLING_FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check the certificate chain of the server */
|
/* check the certificate chain of the server */
|
||||||
@ -836,7 +885,7 @@ open_client_SSL(PGconn *conn)
|
|||||||
libpq_gettext("certificate could not be validated: %s\n"),
|
libpq_gettext("certificate could not be validated: %s\n"),
|
||||||
X509_verify_cert_error_string(r));
|
X509_verify_cert_error_string(r));
|
||||||
close_SSL(conn);
|
close_SSL(conn);
|
||||||
return -1;
|
return PGRES_POLLING_FAILED;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -848,7 +897,7 @@ open_client_SSL(PGconn *conn)
|
|||||||
libpq_gettext("certificate could not be obtained: %s\n"),
|
libpq_gettext("certificate could not be obtained: %s\n"),
|
||||||
SSLerrmessage());
|
SSLerrmessage());
|
||||||
close_SSL(conn);
|
close_SSL(conn);
|
||||||
return -1;
|
return PGRES_POLLING_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
X509_NAME_oneline(X509_get_subject_name(conn->peer),
|
X509_NAME_oneline(X509_get_subject_name(conn->peer),
|
||||||
@ -871,11 +920,12 @@ open_client_SSL(PGconn *conn)
|
|||||||
if (verify_peer(conn) == -1)
|
if (verify_peer(conn) == -1)
|
||||||
{
|
{
|
||||||
close_SSL(conn);
|
close_SSL(conn);
|
||||||
return -1;
|
return PGRES_POLLING_FAILED;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
/* SSL handshake is complete */
|
||||||
|
return PGRES_POLLING_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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.92 2003/04/19 00:02:30 tgl Exp $
|
* $Id: libpq-fe.h,v 1.93 2003/06/08 17:43:00 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -38,9 +38,9 @@ extern "C"
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Although you may decide to change this list in some way, values
|
* Although it is okay to add to this list, values which become unused
|
||||||
* which become unused should never be removed, nor should constants
|
* should never be removed, nor should constants be redefined - that would
|
||||||
* be redefined - that would break compatibility with existing code.
|
* break compatibility with existing code.
|
||||||
*/
|
*/
|
||||||
CONNECTION_OK,
|
CONNECTION_OK,
|
||||||
CONNECTION_BAD,
|
CONNECTION_BAD,
|
||||||
@ -56,7 +56,9 @@ typedef enum
|
|||||||
* postmaster. */
|
* postmaster. */
|
||||||
CONNECTION_AUTH_OK, /* Received authentication; waiting for
|
CONNECTION_AUTH_OK, /* Received authentication; waiting for
|
||||||
* backend startup. */
|
* backend startup. */
|
||||||
CONNECTION_SETENV /* Negotiating environment. */
|
CONNECTION_SETENV, /* Negotiating environment. */
|
||||||
|
CONNECTION_SSL_STARTUP, /* Negotiating SSL. */
|
||||||
|
CONNECTION_NEEDED /* Internal state: connect() needed */
|
||||||
} ConnStatusType;
|
} ConnStatusType;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -71,7 +73,7 @@ typedef enum
|
|||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
PGRES_EMPTY_QUERY = 0,
|
PGRES_EMPTY_QUERY = 0, /* empty query string was executed */
|
||||||
PGRES_COMMAND_OK, /* a query command that doesn't return
|
PGRES_COMMAND_OK, /* a query command that doesn't return
|
||||||
* anything was executed properly by the
|
* anything was executed properly by the
|
||||||
* backend */
|
* backend */
|
||||||
@ -82,8 +84,8 @@ typedef enum
|
|||||||
PGRES_COPY_IN, /* Copy In data transfer in progress */
|
PGRES_COPY_IN, /* Copy In data transfer in progress */
|
||||||
PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from
|
PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from
|
||||||
* the backend */
|
* the backend */
|
||||||
PGRES_NONFATAL_ERROR,
|
PGRES_NONFATAL_ERROR, /* notice or warning message */
|
||||||
PGRES_FATAL_ERROR
|
PGRES_FATAL_ERROR /* query failed */
|
||||||
} ExecStatusType;
|
} ExecStatusType;
|
||||||
|
|
||||||
/* PGconn encapsulates a connection to the backend.
|
/* PGconn encapsulates a connection to the backend.
|
||||||
|
@ -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.70 2003/05/08 18:33:39 tgl Exp $
|
* $Id: libpq-int.h,v 1.71 2003/06/08 17:43:00 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -35,6 +35,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
|
|||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
/* include stuff common to fe and be */
|
/* include stuff common to fe and be */
|
||||||
|
#include "getaddrinfo.h"
|
||||||
#include "libpq/pqcomm.h"
|
#include "libpq/pqcomm.h"
|
||||||
#include "lib/dllist.h"
|
#include "lib/dllist.h"
|
||||||
/* include stuff found in fe only */
|
/* include stuff found in fe only */
|
||||||
@ -45,23 +46,9 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
|
|||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* libpq supports this version of the frontend/backend protocol.
|
|
||||||
*
|
|
||||||
* NB: we used to use PG_PROTOCOL_LATEST from the backend pqcomm.h file,
|
|
||||||
* but that's not really the right thing: just recompiling libpq
|
|
||||||
* against a more recent backend isn't going to magically update it
|
|
||||||
* for most sorts of protocol changes. So, when you change libpq
|
|
||||||
* to support a different protocol revision, you have to change this
|
|
||||||
* constant too. PG_PROTOCOL_EARLIEST and PG_PROTOCOL_LATEST in
|
|
||||||
* pqcomm.h describe what the backend knows, not what libpq knows.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,0)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* POSTGRES backend dependent Constants.
|
* POSTGRES backend dependent Constants.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PQERRORMSG_LENGTH 1024
|
#define PQERRORMSG_LENGTH 1024
|
||||||
#define CMDSTATUS_LEN 40
|
#define CMDSTATUS_LEN 40
|
||||||
|
|
||||||
@ -96,20 +83,22 @@ typedef struct pgresAttDesc
|
|||||||
int atttypmod; /* type-specific modifier info */
|
int atttypmod; /* type-specific modifier info */
|
||||||
} PGresAttDesc;
|
} PGresAttDesc;
|
||||||
|
|
||||||
/* Data for a single attribute of a single tuple */
|
/*
|
||||||
|
* Data for a single attribute of a single tuple
|
||||||
/* We use char* for Attribute values.
|
*
|
||||||
The value pointer always points to a null-terminated area; we add a
|
* We use char* for Attribute values.
|
||||||
null (zero) byte after whatever the backend sends us. This is only
|
*
|
||||||
particularly useful for text tuples ... with a binary value, the
|
* The value pointer always points to a null-terminated area; we add a
|
||||||
value might have embedded nulls, so the application can't use C string
|
* null (zero) byte after whatever the backend sends us. This is only
|
||||||
operators on it. But we add a null anyway for consistency.
|
* particularly useful for text tuples ... with a binary value, the
|
||||||
Note that the value itself does not contain a length word.
|
* value might have embedded nulls, so the application can't use C string
|
||||||
|
* operators on it. But we add a null anyway for consistency.
|
||||||
A NULL attribute is a special case in two ways: its len field is NULL_LEN
|
* Note that the value itself does not contain a length word.
|
||||||
and its value field points to null_field in the owning PGresult. All the
|
*
|
||||||
NULL attributes in a query result point to the same place (there's no need
|
* A NULL attribute is a special case in two ways: its len field is NULL_LEN
|
||||||
to store a null string separately for each one).
|
* and its value field points to null_field in the owning PGresult. All the
|
||||||
|
* NULL attributes in a query result point to the same place (there's no need
|
||||||
|
* to store a null string separately for each one).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define NULL_LEN (-1) /* pg_result len for NULL value */
|
#define NULL_LEN (-1) /* pg_result len for NULL value */
|
||||||
@ -135,15 +124,6 @@ struct pg_result
|
|||||||
int binary; /* binary tuple values if binary == 1,
|
int binary; /* binary tuple values if binary == 1,
|
||||||
* otherwise text */
|
* otherwise text */
|
||||||
|
|
||||||
/*
|
|
||||||
* The conn link in PGresult is no longer used by any libpq code. It
|
|
||||||
* should be removed entirely, because it could be a dangling link
|
|
||||||
* (the application could keep the PGresult around longer than it
|
|
||||||
* keeps the PGconn!) But there may be apps out there that depend on
|
|
||||||
* it, so we will leave it here at least for a release or so.
|
|
||||||
*/
|
|
||||||
PGconn *xconn; /* connection we did the query on, if any */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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.
|
||||||
@ -194,6 +174,35 @@ typedef enum
|
|||||||
PGASYNC_COPY_OUT /* Copy Out data transfer in progress */
|
PGASYNC_COPY_OUT /* Copy Out data transfer in progress */
|
||||||
} PGAsyncStatusType;
|
} PGAsyncStatusType;
|
||||||
|
|
||||||
|
/* PGSetenvStatusType defines the state of the PQSetenv state machine */
|
||||||
|
/* (this is used only for 2.0-protocol connections) */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Typedef for the EnvironmentOptions[] array */
|
||||||
|
typedef struct PQEnvironmentOption
|
||||||
|
{
|
||||||
|
const char *envName, /* name of an environment variable */
|
||||||
|
*pgName; /* name of corresponding SET variable */
|
||||||
|
} PQEnvironmentOption;
|
||||||
|
|
||||||
|
/* Typedef for parameter-status list entries */
|
||||||
|
typedef struct pgParameterStatus
|
||||||
|
{
|
||||||
|
struct pgParameterStatus *next; /* list link */
|
||||||
|
char *name; /* parameter name */
|
||||||
|
char *value; /* parameter value */
|
||||||
|
/* Note: name and value are stored in same malloc block as struct is */
|
||||||
|
} pgParameterStatus;
|
||||||
|
|
||||||
/* large-object-access data ... allocated only if large-object code is used. */
|
/* large-object-access data ... allocated only if large-object code is used. */
|
||||||
typedef struct pgLobjfuncs
|
typedef struct pgLobjfuncs
|
||||||
{
|
{
|
||||||
@ -207,7 +216,8 @@ typedef struct pgLobjfuncs
|
|||||||
Oid fn_lo_write; /* OID of backend function LOwrite */
|
Oid fn_lo_write; /* OID of backend function LOwrite */
|
||||||
} PGlobjfuncs;
|
} PGlobjfuncs;
|
||||||
|
|
||||||
/* PGconn stores all the state data associated with a single connection
|
/*
|
||||||
|
* PGconn stores all the state data associated with a single connection
|
||||||
* to a backend.
|
* to a backend.
|
||||||
*/
|
*/
|
||||||
struct pg_conn
|
struct pg_conn
|
||||||
@ -254,12 +264,21 @@ struct pg_conn
|
|||||||
SockAddr laddr; /* Local address */
|
SockAddr laddr; /* Local address */
|
||||||
SockAddr raddr; /* Remote address */
|
SockAddr raddr; /* Remote address */
|
||||||
int raddr_len; /* Length of remote address */
|
int raddr_len; /* Length of remote address */
|
||||||
|
ProtocolVersion pversion; /* FE/BE protocol version in use */
|
||||||
|
char sversion[8]; /* The first few bytes of server version */
|
||||||
|
|
||||||
|
/* Transient state needed while establishing connection */
|
||||||
|
struct addrinfo *addrlist; /* list of possible backend addresses */
|
||||||
|
struct addrinfo *addr_cur; /* the one currently being tried */
|
||||||
|
PGSetenvStatusType setenv_state; /* for 2.0 protocol only */
|
||||||
|
const PQEnvironmentOption *next_eo;
|
||||||
|
|
||||||
/* Miscellaneous stuff */
|
/* Miscellaneous stuff */
|
||||||
int be_pid; /* PID of backend --- needed for cancels */
|
int be_pid; /* PID of backend --- needed for cancels */
|
||||||
int be_key; /* key of backend --- needed for cancels */
|
int be_key; /* key of backend --- needed for cancels */
|
||||||
char md5Salt[4]; /* password salt received from backend */
|
char md5Salt[4]; /* password salt received from backend */
|
||||||
char cryptSalt[2]; /* password salt received from backend */
|
char cryptSalt[2]; /* password salt received from backend */
|
||||||
|
pgParameterStatus *pstatus; /* ParameterStatus data */
|
||||||
int client_encoding; /* encoding id */
|
int client_encoding; /* encoding id */
|
||||||
PGlobjfuncs *lobjfuncs; /* private state for large-object access
|
PGlobjfuncs *lobjfuncs; /* private state for large-object access
|
||||||
* fns */
|
* fns */
|
||||||
@ -279,7 +298,8 @@ struct pg_conn
|
|||||||
int outCount; /* number of chars waiting in buffer */
|
int outCount; /* number of chars waiting in buffer */
|
||||||
|
|
||||||
/* State for constructing messages in outBuffer */
|
/* State for constructing messages in outBuffer */
|
||||||
int outMsgStart; /* offset to msg start (length word) */
|
int outMsgStart; /* offset to msg start (length word);
|
||||||
|
* if -1, msg has no length word */
|
||||||
int outMsgEnd; /* offset to msg end (so far) */
|
int outMsgEnd; /* offset to msg end (so far) */
|
||||||
|
|
||||||
/* Status for asynchronous result construction */
|
/* Status for asynchronous result construction */
|
||||||
@ -324,10 +344,46 @@ extern int pqPacketSend(PGconn *conn, char pack_type,
|
|||||||
/* === in fe-exec.c === */
|
/* === in fe-exec.c === */
|
||||||
|
|
||||||
extern void pqSetResultError(PGresult *res, const char *msg);
|
extern void pqSetResultError(PGresult *res, const char *msg);
|
||||||
|
extern void pqCatenateResultError(PGresult *res, const char *msg);
|
||||||
extern void *pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary);
|
extern void *pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary);
|
||||||
extern char *pqResultStrdup(PGresult *res, const char *str);
|
extern char *pqResultStrdup(PGresult *res, const char *str);
|
||||||
extern void pqClearAsyncResult(PGconn *conn);
|
extern void pqClearAsyncResult(PGconn *conn);
|
||||||
extern int pqGetErrorNotice(PGconn *conn, bool isError);
|
extern void pqSaveErrorResult(PGconn *conn);
|
||||||
|
extern PGresult *pqPrepareAsyncResult(PGconn *conn);
|
||||||
|
extern int pqAddTuple(PGresult *res, PGresAttValue *tup);
|
||||||
|
extern void pqSaveParameterStatus(PGconn *conn, const char *name,
|
||||||
|
const char *value);
|
||||||
|
extern const char *pqGetParameterStatus(PGconn *conn, const char *name);
|
||||||
|
extern void pqHandleSendFailure(PGconn *conn);
|
||||||
|
|
||||||
|
/* === in fe-protocol2.c === */
|
||||||
|
|
||||||
|
extern PostgresPollingStatusType pqSetenvPoll(PGconn *conn);
|
||||||
|
|
||||||
|
extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen,
|
||||||
|
const PQEnvironmentOption *options);
|
||||||
|
extern void pqParseInput2(PGconn *conn);
|
||||||
|
extern int pqGetline2(PGconn *conn, char *s, int maxlen);
|
||||||
|
extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize);
|
||||||
|
extern int pqEndcopy2(PGconn *conn);
|
||||||
|
extern PGresult *pqFunctionCall2(PGconn *conn, Oid fnid,
|
||||||
|
int *result_buf, int *actual_result_len,
|
||||||
|
int result_is_int,
|
||||||
|
const PQArgBlock *args, int nargs);
|
||||||
|
|
||||||
|
/* === in fe-protocol3.c === */
|
||||||
|
|
||||||
|
extern char *pqBuildStartupPacket3(PGconn *conn, int *packetlen,
|
||||||
|
const PQEnvironmentOption *options);
|
||||||
|
extern void pqParseInput3(PGconn *conn);
|
||||||
|
extern int pqGetErrorNotice3(PGconn *conn, bool isError);
|
||||||
|
extern int pqGetline3(PGconn *conn, char *s, int maxlen);
|
||||||
|
extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize);
|
||||||
|
extern int pqEndcopy3(PGconn *conn);
|
||||||
|
extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid,
|
||||||
|
int *result_buf, int *actual_result_len,
|
||||||
|
int result_is_int,
|
||||||
|
const PQArgBlock *args, int nargs);
|
||||||
|
|
||||||
/* === in fe-misc.c === */
|
/* === in fe-misc.c === */
|
||||||
|
|
||||||
@ -345,7 +401,7 @@ extern int pqGetnchar(char *s, size_t len, PGconn *conn);
|
|||||||
extern int pqPutnchar(const char *s, size_t len, PGconn *conn);
|
extern int pqPutnchar(const char *s, size_t len, PGconn *conn);
|
||||||
extern int pqGetInt(int *result, size_t bytes, PGconn *conn);
|
extern int pqGetInt(int *result, size_t bytes, PGconn *conn);
|
||||||
extern int pqPutInt(int value, size_t bytes, PGconn *conn);
|
extern int pqPutInt(int value, size_t bytes, PGconn *conn);
|
||||||
extern int pqPutMsgStart(char msg_type, PGconn *conn);
|
extern int pqPutMsgStart(char msg_type, bool force_len, PGconn *conn);
|
||||||
extern int pqPutMsgEnd(PGconn *conn);
|
extern int pqPutMsgEnd(PGconn *conn);
|
||||||
extern int pqReadData(PGconn *conn);
|
extern int pqReadData(PGconn *conn);
|
||||||
extern int pqFlush(PGconn *conn);
|
extern int pqFlush(PGconn *conn);
|
||||||
@ -359,21 +415,14 @@ extern int pqWriteReady(PGconn *conn);
|
|||||||
|
|
||||||
extern int pqsecure_initialize(PGconn *);
|
extern int pqsecure_initialize(PGconn *);
|
||||||
extern void pqsecure_destroy(void);
|
extern void pqsecure_destroy(void);
|
||||||
extern int pqsecure_open_client(PGconn *);
|
extern PostgresPollingStatusType pqsecure_open_client(PGconn *);
|
||||||
extern void pqsecure_close(PGconn *);
|
extern void pqsecure_close(PGconn *);
|
||||||
extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len);
|
extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len);
|
||||||
extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len);
|
extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len);
|
||||||
|
|
||||||
/* bits in a byte */
|
/* Note: PGDONOTICE macro will work if applied to either PGconn or PGresult */
|
||||||
#define BYTELEN 8
|
#define PGDONOTICE(conn,message) \
|
||||||
|
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
||||||
/* fall back options if they are not specified by arguments or defined
|
|
||||||
by environment variables */
|
|
||||||
#define DefaultHost "localhost"
|
|
||||||
#define DefaultTty ""
|
|
||||||
#define DefaultOption ""
|
|
||||||
#define DefaultAuthtype ""
|
|
||||||
#define DefaultPassword ""
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this is so that we can check is a connection is non-blocking internally
|
* this is so that we can check is a connection is non-blocking internally
|
||||||
|
Loading…
Reference in New Issue
Block a user