提交 510a20b6 编写于 作者: A Adam Lee 提交者: Adam Lee

Retire gp_libpq_fe part 1, libpq itself

    commit b0328d5631088cca5f80acc8dd85b859f062ebb0
    Author: mcdevc <a@b>
    Date:   Fri Mar 6 16:28:45 2009 -0800

        Separate our internal libpq front end from the client libpq library
        upgrade libpq to the latest to pick up bug fixes and support for more
        client authentication types (GSSAPI, KRB5, etc)
        Upgrade all files dependent on libpq to handle new version.

Above is the initial commit of gp_libpq_fe, seems no good reasons still
having it.

Key things this PR do:

1, remove the gp_libpq_fe directory.
2, build libpq source codes into two versions, for frontend and backend,
check the macro FRONTEND.
3, libpq for backend still bypasses local authentication, SSL and some
environment variables, and these are the whole differences.
Signed-off-by: NAdam Lee <ali@pivotal.io>
上级 15fdc144
......@@ -300,13 +300,6 @@ throughout the codebase, but a few larger additions worth noting:
between the DXL format used by ORCA, and the PostgreSQL internal
representation.
* __src/backend/gp_libpq_fe/__
A slightly modified copy of libpq. The master node uses this to
connect to segments, and to send fragments of a query plan to
segments for execution. It is linked directly into the backend, it
is not a shared library like libpq.
* __src/backend/fts/__
FTS is a process that runs in the master node, and periodically
......
......@@ -14,6 +14,7 @@ include Makefile.global
all install installdirs uninstall distprep:
$(MAKE) -C interfaces/libpq $@
$(MAKE) -C port $@
$(MAKE) -C timezone $@
$(MAKE) -C backend $@
......
......@@ -21,8 +21,8 @@ include $(BLD_TOP)/$(ADDON_DIR)/src/Makefile
endif
SUBDIRS = access bootstrap catalog parser commands executor \
fts lib libpq gp_libpq_fe main nodes optimizer port postmaster regex \
replication rewrite storage tcop tsearch utils $(top_builddir)/src/timezone cdb\
fts lib libpq main nodes optimizer port postmaster regex \
replication rewrite storage tcop tsearch utils $(top_builddir)/src/timezone cdb \
$(ADDON_SUBDIR)
ifeq ($(enable_orca),yes)
......@@ -67,6 +67,9 @@ endif
# Greenplum uses threads in the backend
LIBS := $(LIBS) -lpthread
# Greenplum uses libpq to communicate between QD and QEs
OBJS := $(OBJS) $(addprefix $(top_builddir)/src/interfaces/libpq/,fe-protocol3_for_backend.o fe-connect_for_backend.o fe-exec.o pqexpbuffer.o fe-auth.o fe-misc.o fe-protocol2.o fe-secure.o getpeereid.o)
##########################################################################
all: submake-libpgport postgres $(POSTGRES_IMP)
......
......@@ -11,5 +11,5 @@ include $(top_builddir)/src/Makefile.global
override CPPFLAGS += -I$(top_srcdir)/src/backend/gp_libpq_fe -I$(top_srcdir)/src/port -I$(top_srcdir)/src/backend/utils/misc
OBJS = cdbconn.o cdbdisp.o cdbdisp_thread.o cdbdisp_async.o cdbdispatchresult.o cdbdisp_dtx.o cdbdisp_query.o cdbgang.o cdbgang_thread.o cdbgang_async.o
OBJS = cdbconn.o cdbdisp.o cdbdisp_thread.o cdbdisp_async.o cdbdispatchresult.o cdbdisp_dtx.o cdbdisp_query.o cdbgang.o cdbgang_thread.o cdbgang_async.o cdbpq.o
include $(top_srcdir)/src/backend/common.mk
......@@ -35,6 +35,7 @@
#include "cdb/cdbfts.h"
#include "cdb/cdbgang.h"
#include "cdb/cdbvars.h"
#include "cdb/cdbpq.h"
#include "miscadmin.h"
#define DISPATCH_WAIT_TIMEOUT_MSEC 2000
......
......@@ -36,6 +36,7 @@
#include "cdb/cdbfts.h"
#include "cdb/cdbgang.h"
#include "cdb/cdbvars.h"
#include "cdb/cdbpq.h"
#include "miscadmin.h"
#include "port/atomics.h"
......
......@@ -970,3 +970,50 @@ cdbdisp_snatchPGresults(CdbDispatchResult *dispatchResult,
return nresults;
}
struct HTAB *
PQprocessAoTupCounts(struct PartitionNode *parts, struct HTAB *ht,
void *aotupcounts, int naotupcounts)
{
PQaoRelTupCount *ao = (PQaoRelTupCount *) aotupcounts;
if (naotupcounts)
{
int j;
for (j = 0; j < naotupcounts; j++)
{
if (OidIsValid(ao->aorelid))
{
bool found;
PQaoRelTupCount *entry;
if (!ht)
{
HASHCTL ctl;
/*
* reasonable assumption?
*/
long num_buckets = list_length(all_partition_relids(parts));
num_buckets /= num_partition_levels(parts);
ctl.keysize = sizeof(Oid);
ctl.entrysize = sizeof(*entry);
ht = hash_create("AO hash map", num_buckets, &ctl, HASH_ELEM);
}
entry = hash_search(ht, &(ao->aorelid), HASH_ENTER, &found);
if (found)
entry->tupcount += ao->tupcount;
else
entry->tupcount = ao->tupcount;
}
ao++;
}
}
return ht;
}
#include "libpq-fe.h"
#include "libpq-int.h"
#include "cdb/cdbpq.h"
int
PQsendGpQuery_shared(PGconn *conn, char *shared_query, int query_len, bool nonblock)
{
int ret;
if (!PQsendQueryStart(conn))
return 0;
if (!shared_query)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("shared mpp-query string is a null pointer\n"));
return 0;
}
if (conn->outBuffer_shared)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("Cannot overwrite shared query string\n"));
return 0;
}
/*
* Stash the original buffer and switch to the incoming pointer.
* We will restore the buffer after completing to send the shared query.
*/
conn->outBufferSaved = conn->outBuffer;
conn->outBuffer = shared_query;
conn->outBuffer_shared = true;
conn->outMsgStart = 0;
conn->outMsgEnd = query_len;
conn->outCount = query_len;
/* remember we are using simple query protocol */
conn->queryclass = PGQUERY_SIMPLE;
/*
* Give the data a push. In nonblock mode, don't complain if we're unable
* to send it all; PQgetResult() will do any additional flushing needed.
*/
if (nonblock)
ret = pqFlushNonBlocking(conn);
else
ret = pqFlush(conn);
if (ret < 0)
{
pqHandleSendFailure(conn);
return 0;
}
/* OK, it's launched! */
conn->asyncStatus = PGASYNC_BUSY;
return 1;
}
#-------------------------------------------------------------------------
#
# Makefile--
# Makefile for gp_libpq_fe subsystem (internal frontend half of libpq to talk from MasterSeg to SegDBs)
#
# IDENTIFICATION
#
#-------------------------------------------------------------------------
subdir = src/backend/gp_libpq_fe
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -DUNSAFE_STAT_OK -I$(srcdir) $(CPPFLAGS) -I$(top_builddir)/src/port
ifneq ($(PORTNAME), win32)
override CFLAGS += $(PTHREAD_CFLAGS)
endif
OBJS = fe-exec.o pqexpbuffer.o \
fe-auth.o \
fe-connect.o fe-misc.o fe-protocol3.o
ifeq ($(PORTNAME), win32)
OBJS += win32.o
endif
include $(top_srcdir)/src/backend/common.mk
\ No newline at end of file
/*-------------------------------------------------------------------------
*
* fe-auth.c
* The front-end (client) authorization routines
*
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.144.4.1 2010/07/14 17:09:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* frontend (client) routines:
* pg_fe_sendauth send authentication information
* pg_fe_getauthname get user's name according to the client side
* of the authentication system
*/
#include "postgres.h"
#ifdef WIN32
#include "win32.h"
#else
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
#include <sys/socket.h>
#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
#include <sys/uio.h>
#include <sys/ucred.h>
#endif
#ifndef MAXHOSTNAMELEN
#include <netdb.h> /* for MAXHOSTNAMELEN on some */
#endif
#include <pwd.h>
#endif
#ifdef HAVE_CRYPT_H
/* Is this include obsolete? */
#include <crypt.h>
#endif
#include "gp-libpq-fe.h"
#include "gp-fe-auth.h"
#include "libpq/md5.h"
/*
* Respond to AUTH_REQ_SCM_CREDS challenge.
*
* Note: current backends will not use this challenge if HAVE_GETPEEREID
* or SO_PEERCRED is defined, but pre-7.4 backends might, so compile the
* code anyway.
*/
static int
pg_local_sendauth(PGconn *conn)
{
#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
char buf;
struct iovec iov;
struct msghdr msg;
#ifdef HAVE_STRUCT_CMSGCRED
/* Prevent padding */
char cmsgmem[sizeof(struct cmsghdr) + sizeof(struct cmsgcred)];
/* Point to start of first structure */
struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
#endif
/*
* The backend doesn't care what we send here, but it wants exactly one
* character to force recvmsg() to block and wait for us.
*/
buf = '\0';
iov.iov_base = &buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
#ifdef HAVE_STRUCT_CMSGCRED
/* Create control header, FreeBSD */
msg.msg_control = cmsg;
msg.msg_controllen = sizeof(cmsgmem);
memset(cmsg, 0, sizeof(cmsgmem));
cmsg->cmsg_len = sizeof(cmsgmem);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_CREDS;
#endif
if (sendmsg(conn->sock, &msg, 0) == -1)
{
char sebuf[256];
printfPQExpBuffer(&conn->errorMessage,
"pg_local_sendauth: sendmsg: %s\n",
pqStrerror(errno, sebuf, sizeof(sebuf)));
return STATUS_ERROR;
}
return STATUS_OK;
#else
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SCM_CRED authentication method not supported\n"));
return STATUS_ERROR;
#endif
}
static int
pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
{
int ret;
char *crypt_pwd;
/* Encrypt the password if needed. */
switch (areq)
{
case AUTH_REQ_MD5:
{
char *crypt_pwd2;
/* Allocate enough space for two MD5 hashes */
crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
if (!crypt_pwd)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n"));
return STATUS_ERROR;
}
crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
if (!pg_md5_encrypt(password, conn->pguser,
strlen(conn->pguser), crypt_pwd2))
{
free(crypt_pwd);
return STATUS_ERROR;
}
if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), conn->md5Salt,
sizeof(conn->md5Salt), crypt_pwd))
{
free(crypt_pwd);
return STATUS_ERROR;
}
break;
}
case AUTH_REQ_PASSWORD:
/* discard const so we can assign it */
crypt_pwd = (char *) password;
break;
default:
return STATUS_ERROR;
}
/* 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)
free(crypt_pwd);
return ret;
}
/*
* pg_fe_sendauth
* client demux routine for outgoing authentication information
*/
int
pg_fe_sendauth(AuthRequest areq, PGconn *conn)
{
switch (areq)
{
case AUTH_REQ_OK:
break;
case AUTH_REQ_KRB4:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("Kerberos 4 authentication not supported\n"));
return STATUS_ERROR;
case AUTH_REQ_KRB5:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("Kerberos 5 authentication not supported\n"));
return STATUS_ERROR;
case AUTH_REQ_GSS:
case AUTH_REQ_GSS_CONT:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("GSSAPI authentication not supported\n"));
return STATUS_ERROR;
case AUTH_REQ_SSPI:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSPI authentication not supported\n"));
return STATUS_ERROR;
case AUTH_REQ_CRYPT:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("Crypt authentication not supported\n"));
return STATUS_ERROR;
case AUTH_REQ_MD5:
case AUTH_REQ_PASSWORD:
conn->password_needed = true;
if (conn->pgpass == NULL || conn->pgpass[0] == '\0')
{
printfPQExpBuffer(&conn->errorMessage,
PQnoPasswordSupplied);
return STATUS_ERROR;
}
if (pg_password_sendauth(conn, conn->pgpass, areq) != STATUS_OK)
{
printfPQExpBuffer(&conn->errorMessage,
"fe_sendauth: error sending password authentication\n");
return STATUS_ERROR;
}
break;
case AUTH_REQ_SCM_CREDS:
if (pg_local_sendauth(conn) != STATUS_OK)
return STATUS_ERROR;
break;
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("authentication method %u not supported\n"), areq);
return STATUS_ERROR;
}
return STATUS_OK;
}
/*
* pg_fe_getauthname -- returns a pointer to dynamic space containing whatever
* name the user has authenticated to the system
*
* if there is an error, return NULL with an error message in errorMessage
*/
char *
pg_fe_getauthname(PQExpBuffer errorMessage)
{
const char *name = NULL;
char *authn;
#ifdef WIN32
char username[128];
DWORD namesize = sizeof(username) - 1;
#else
char pwdbuf[BUFSIZ];
struct passwd pwdstr;
struct passwd *pw = NULL;
#endif
/*
* Some users are using configure --enable-thread-safety-force, so we
* might as well do the locking within our library to protect
* pqGetpwuid(). In fact, application developers can use getpwuid() in
* their application if they use the locking call we provide, or install
* their own locking function using PQregisterThreadLock().
*/
pglock_thread();
if (!name)
{
#ifdef WIN32
if (GetUserName(username, &namesize))
name = username;
#else
if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pw) == 0)
name = pw->pw_name;
#endif
}
authn = name ? strdup(name) : NULL;
pgunlock_thread();
return authn;
}
/*
* PQencryptPassword -- exported routine to encrypt a password
*
* This is intended to be used by client applications that wish to send
* commands like ALTER USER joe PASSWORD 'pwd'. The password need not
* be sent in cleartext if it is encrypted on the client side. This is
* good because it ensures the cleartext password won't end up in logs,
* pg_stat displays, etc. We export the function so that clients won't
* be dependent on low-level details like whether the enceyption is MD5
* or something else.
*
* Arguments are the cleartext password, and the SQL name of the user it
* is for.
*
* Return value is a malloc'd string, or NULL if out-of-memory. The client
* may assume the string doesn't contain any special characters that would
* require escaping.
*/
char *
PQencryptPassword(const char *passwd, const char *user)
{
char *crypt_pwd;
crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
if (!crypt_pwd)
return NULL;
if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd))
{
free(crypt_pwd);
return NULL;
}
return crypt_pwd;
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*-------------------------------------------------------------------------
*
* gp-fe-auth.h
*
* Definitions for network authentication routines
*
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/gp_libpq_fe/gp-fe-auth.h
*
*-------------------------------------------------------------------------
*/
#ifndef FE_AUTH_H
#define FE_AUTH_H
#include "gp-libpq-fe.h"
#include "gp-libpq-int.h"
extern int pg_fe_sendauth(AuthRequest areq, PGconn *conn);
extern char *pg_fe_getauthname(PQExpBuffer errorMessage);
#endif /* FE_AUTH_H */
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*-------------------------------------------------------------------------
*
* pqexpbuffer.h
* Declarations/definitions for "PQExpBuffer" functions.
*
* PQExpBuffer provides an indefinitely-extensible string data type.
* It can be used to buffer either ordinary C strings (null-terminated text)
* or arbitrary binary data. All storage is allocated with malloc().
*
* This module is essentially the same as the backend's StringInfo data type,
* but it is intended for use in frontend libpq and client applications.
* Thus, it does not rely on palloc() nor elog().
*
* It does rely on vsnprintf(); if configure finds that libc doesn't provide
* a usable vsnprintf(), then a copy of our own implementation of it will
* be linked into libpq.
*
* Portions Copyright (c) 2005-2010, Greenplum inc
* Portions Copyright (c) 2012-Present Pivotal Software, Inc.
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/gp_libpq_fe/pqexpbuffer.h
*
* $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.h,v 1.24 2010/01/02 16:58:12 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PQEXPBUFFER_H
#define PQEXPBUFFER_H
/*-------------------------
* PQExpBufferData holds information about an extensible string.
* data is the current buffer for the string (allocated with malloc).
* len is the current string length. There is guaranteed to be
* a terminating '\0' at data[len], although this is not very
* useful when the string holds binary data rather than text.
* maxlen is the allocated size in bytes of 'data', i.e. the maximum
* string size (including the terminating '\0' char) that we can
* currently store in 'data' without having to reallocate
* more space. We must always have maxlen > len.
*
* An exception occurs if we failed to allocate enough memory for the string
* buffer. In that case data points to a statically allocated empty string,
* and len = maxlen = 0.
*-------------------------
*/
typedef struct PQExpBufferData
{
char *data;
size_t len;
size_t maxlen;
} PQExpBufferData;
typedef PQExpBufferData *PQExpBuffer;
/*------------------------
* Test for a broken (out of memory) PQExpBuffer.
* When a buffer is "broken", all operations except resetting or deleting it
* are no-ops.
*------------------------
*/
#define PQExpBufferBroken(str) \
((str) == NULL || (str)->maxlen == 0)
/*------------------------
* Same, but for use when using a static or local PQExpBufferData struct.
* For that, a null-pointer test is useless and may draw compiler warnings.
*------------------------
*/
#define PQExpBufferDataBroken(buf) \
((buf).maxlen == 0)
/*------------------------
* Initial size of the data buffer in a PQExpBuffer.
* NB: this must be large enough to hold error messages that might
* be returned by PQrequestCancel().
*------------------------
*/
#define INITIAL_EXPBUFFER_SIZE 256
/*------------------------
* There are two ways to create a PQExpBuffer object initially:
*
* PQExpBuffer stringptr = createPQExpBuffer();
* Both the PQExpBufferData and the data buffer are malloc'd.
*
* PQExpBufferData string;
* initPQExpBuffer(&string);
* The data buffer is malloc'd but the PQExpBufferData is presupplied.
* This is appropriate if the PQExpBufferData is a field of another
* struct.
*-------------------------
*/
/*------------------------
* createPQExpBuffer
* Create an empty 'PQExpBufferData' & return a pointer to it.
*/
extern PQExpBuffer createPQExpBuffer(void);
/*------------------------
* initPQExpBuffer
* Initialize a PQExpBufferData struct (with previously undefined contents)
* to describe an empty string.
*/
extern void initPQExpBuffer(PQExpBuffer str);
/*------------------------
* To destroy a PQExpBuffer, use either:
*
* destroyPQExpBuffer(str);
* free()s both the data buffer and the PQExpBufferData.
* This is the inverse of createPQExpBuffer().
*
* termPQExpBuffer(str)
* free()s the data buffer but not the PQExpBufferData itself.
* This is the inverse of initPQExpBuffer().
*
* NOTE: some routines build up a string using PQExpBuffer, and then
* release the PQExpBufferData but return the data string itself to their
* caller. At that point the data string looks like a plain malloc'd
* string.
*/
extern void destroyPQExpBuffer(PQExpBuffer str);
extern void termPQExpBuffer(PQExpBuffer str);
/*------------------------
* resetPQExpBuffer
* Reset a PQExpBuffer to empty
*
* Note: if possible, a "broken" PQExpBuffer is returned to normal.
*/
extern void resetPQExpBuffer(PQExpBuffer str);
/*------------------------
* enlargePQExpBuffer
* Make sure there is enough space for 'needed' more bytes in the buffer
* ('needed' does not include the terminating null).
*
* Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case
* the buffer is left in "broken" state.)
*/
extern int enlargePQExpBuffer(PQExpBuffer str, size_t needed);
/*------------------------
* printfPQExpBuffer
* Format text data under the control of fmt (an sprintf-like format string)
* and insert it into str. More space is allocated to str if necessary.
* This is a convenience routine that does the same thing as
* resetPQExpBuffer() followed by appendPQExpBuffer().
*/
extern void
printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
/* This extension allows gcc to check the format string */
__attribute__((format(printf, 2, 3)));
/*------------------------
* appendPQExpBuffer
* Format text data under the control of fmt (an sprintf-like format string)
* and append it to whatever is already in str. More space is allocated
* to str if necessary. This is sort of like a combination of sprintf and
* strcat.
*/
extern void
appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
/* This extension allows gcc to check the format string */
__attribute__((format(printf, 2, 3)));
/*------------------------
* appendPQExpBufferVA
* A version of appendPQExpBuffer() that takes a variable arguments list
* (va_list) instead of '...', like vsnprintf(). Caller must do
* va_start(args, x) before calling, and va_end(args) upon return.
*/
void
appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args);
/*------------------------
* appendPQExpBufferStr
* Append the given string to a PQExpBuffer, allocating more space
* if necessary.
*/
extern void appendPQExpBufferStr(PQExpBuffer str, const char *data);
/*------------------------
* appendPQExpBufferChar
* Append a single byte to str.
* Like appendPQExpBuffer(str, "%c", ch) but much faster.
*/
extern void appendPQExpBufferChar(PQExpBuffer str, char ch);
/*------------------------
* appendBinaryPQExpBuffer
* Append arbitrary binary data to a PQExpBuffer, allocating more space
* if necessary.
*/
extern void appendBinaryPQExpBuffer(PQExpBuffer str,
const char *data, size_t datalen);
#endif /* PQEXPBUFFER_H */
此差异已折叠。
/*
* $PostgreSQL: pgsql/src/interfaces/libpq/win32.h,v 1.30 2009/06/11 14:49:14 momjian Exp $
*/
#ifndef __win32_h_included
#define __win32_h_included
/*
* Some compatibility functions
*/
#ifdef __BORLANDC__
#define _timeb timeb
#define _ftime(a) ftime(a)
#define _errno errno
#define popen(a,b) _popen(a,b)
#else
/* open provided elsewhere */
#define close(a) _close(a)
#define read(a,b,c) _read(a,b,c)
#define write(a,b,c) _write(a,b,c)
#endif
#undef EAGAIN /* doesn't apply on sockets */
#undef EINTR
#define EINTR WSAEINTR
#undef EWOULDBOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#undef ECONNRESET
#define ECONNRESET WSAECONNRESET
#undef EINPROGRESS
#define EINPROGRESS WSAEINPROGRESS
/*
* support for handling Windows Socket errors
*/
extern const char *winsock_strerror(int err, char *strerrbuf, size_t buflen);
#endif
......@@ -342,4 +342,8 @@ cdbdisp_makeDispatchResults(int sliceCapacity,
void
cdbdisp_clearCdbPgResults(CdbPgResults* cdb_pgresults);
extern struct HTAB *
PQprocessAoTupCounts(struct PartitionNode *parts, struct HTAB *ht,
void *aotupcounts, int naotupcounts);
#endif /* CDBDISPATCHRESULT_H */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册