Use poll(2) in preference to select(2), if available. This solves
problems in applications that may have a large number of files open, such that libpq's socket number exceeds the range supported by fd_set. From Chris Brown.
This commit is contained in:
parent
235d5fa666
commit
1d57374114
7
configure
vendored
7
configure
vendored
@ -6888,7 +6888,9 @@ done
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
for ac_header in crypt.h dld.h endian.h fp_class.h getopt.h ieeefp.h pwd.h sys/ipc.h sys/pstat.h sys/select.h sys/sem.h sys/socket.h sys/shm.h sys/un.h termios.h utime.h kernel/OS.h kernel/image.h SupportDefs.h
|
|
||||||
|
|
||||||
|
for ac_header in crypt.h dld.h endian.h fp_class.h getopt.h ieeefp.h poll.h pwd.h sys/ipc.h sys/poll.h sys/pstat.h sys/select.h sys/sem.h sys/socket.h sys/shm.h sys/un.h termios.h utime.h kernel/OS.h kernel/image.h SupportDefs.h
|
||||||
do
|
do
|
||||||
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
if eval "test \"\${$as_ac_Header+set}\" = set"; then
|
if eval "test \"\${$as_ac_Header+set}\" = set"; then
|
||||||
@ -10175,7 +10177,8 @@ test $ac_cv_func_memcmp_working = no && LIBOBJS="$LIBOBJS memcmp.$ac_objext"
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
for ac_func in cbrt fcvt getpeereid memmove pstat setproctitle setsid sigprocmask sysconf waitpid dlopen fdatasync utime utimes
|
|
||||||
|
for ac_func in cbrt dlopen fcvt fdatasync getpeereid memmove poll pstat setproctitle setsid sigprocmask sysconf utime utimes waitpid
|
||||||
do
|
do
|
||||||
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||||
echo "$as_me:$LINENO: checking for $ac_func" >&5
|
echo "$as_me:$LINENO: checking for $ac_func" >&5
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
dnl Process this file with autoconf to produce a configure script.
|
dnl Process this file with autoconf to produce a configure script.
|
||||||
dnl $Header: /cvsroot/pgsql/configure.in,v 1.237 2003/02/19 04:04:04 momjian Exp $
|
dnl $Header: /cvsroot/pgsql/configure.in,v 1.238 2003/03/06 03:16:55 tgl Exp $
|
||||||
dnl
|
dnl
|
||||||
dnl Developers, please strive to achieve this order:
|
dnl Developers, please strive to achieve this order:
|
||||||
dnl
|
dnl
|
||||||
@ -675,7 +675,7 @@ fi
|
|||||||
##
|
##
|
||||||
|
|
||||||
dnl sys/socket.h is required by AC_FUNC_ACCEPT_ARGTYPES
|
dnl sys/socket.h is required by AC_FUNC_ACCEPT_ARGTYPES
|
||||||
AC_CHECK_HEADERS([crypt.h dld.h endian.h fp_class.h getopt.h ieeefp.h pwd.h sys/ipc.h sys/pstat.h sys/select.h sys/sem.h sys/socket.h sys/shm.h sys/un.h termios.h utime.h kernel/OS.h kernel/image.h SupportDefs.h])
|
AC_CHECK_HEADERS([crypt.h dld.h endian.h fp_class.h getopt.h ieeefp.h poll.h pwd.h sys/ipc.h sys/poll.h sys/pstat.h sys/select.h sys/sem.h sys/socket.h sys/shm.h sys/un.h termios.h utime.h kernel/OS.h kernel/image.h SupportDefs.h])
|
||||||
|
|
||||||
# At least on IRIX, cpp test for netinet/tcp.h will fail unless
|
# At least on IRIX, cpp test for netinet/tcp.h will fail unless
|
||||||
# netinet/in.h is included first.
|
# netinet/in.h is included first.
|
||||||
@ -786,7 +786,7 @@ PGAC_FUNC_GETTIMEOFDAY_1ARG
|
|||||||
# SunOS doesn't handle negative byte comparisons properly with +/- return
|
# SunOS doesn't handle negative byte comparisons properly with +/- return
|
||||||
AC_FUNC_MEMCMP
|
AC_FUNC_MEMCMP
|
||||||
|
|
||||||
AC_CHECK_FUNCS([cbrt fcvt getpeereid memmove pstat setproctitle setsid sigprocmask sysconf waitpid dlopen fdatasync utime utimes])
|
AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getpeereid memmove poll pstat setproctitle setsid sigprocmask sysconf utime utimes waitpid])
|
||||||
|
|
||||||
AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
|
AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* or in pg_config.h afterwards. Of course, if you edit pg_config.h, then your
|
* or in pg_config.h afterwards. Of course, if you edit pg_config.h, then your
|
||||||
* changes will be overwritten the next time you run configure.
|
* changes will be overwritten the next time you run configure.
|
||||||
*
|
*
|
||||||
* $Id: pg_config.h.in,v 1.40 2003/02/19 04:04:04 momjian Exp $
|
* $Id: pg_config.h.in,v 1.41 2003/03/06 03:16:55 tgl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PG_CONFIG_H
|
#ifndef PG_CONFIG_H
|
||||||
@ -341,6 +341,12 @@
|
|||||||
/* Set to 1 if you have <ieeefp.h> */
|
/* Set to 1 if you have <ieeefp.h> */
|
||||||
#undef HAVE_IEEEFP_H
|
#undef HAVE_IEEEFP_H
|
||||||
|
|
||||||
|
/* Set to 1 if you have <poll.h> */
|
||||||
|
#undef HAVE_POLL_H
|
||||||
|
|
||||||
|
/* Set to 1 if you have <sys/poll.h> */
|
||||||
|
#undef HAVE_SYS_POLL_H
|
||||||
|
|
||||||
/* Set to 1 if you have <netinet/tcp.h> */
|
/* Set to 1 if you have <netinet/tcp.h> */
|
||||||
#undef HAVE_NETINET_TCP_H
|
#undef HAVE_NETINET_TCP_H
|
||||||
|
|
||||||
@ -649,6 +655,12 @@
|
|||||||
/* Define if you have on_exit() */
|
/* Define if you have on_exit() */
|
||||||
#undef HAVE_ON_EXIT
|
#undef HAVE_ON_EXIT
|
||||||
|
|
||||||
|
/* Define if you have syslog() */
|
||||||
|
#undef HAVE_SYSLOG
|
||||||
|
|
||||||
|
/* Define if you have poll() */
|
||||||
|
#undef HAVE_POLL
|
||||||
|
|
||||||
/* Define if the corresponding types are defined in standard headers */
|
/* Define if the corresponding types are defined in standard headers */
|
||||||
#undef HAVE_INT8
|
#undef HAVE_INT8
|
||||||
#undef HAVE_UINT8
|
#undef HAVE_UINT8
|
||||||
@ -656,9 +668,6 @@
|
|||||||
#undef HAVE_UINT64
|
#undef HAVE_UINT64
|
||||||
#undef HAVE_SIG_ATOMIC_T
|
#undef HAVE_SIG_ATOMIC_T
|
||||||
|
|
||||||
/* Define if you have syslog() */
|
|
||||||
#undef HAVE_SYSLOG
|
|
||||||
|
|
||||||
/* Define exactly one of these symbols to select semaphore implementation */
|
/* Define exactly one of these symbols to select semaphore implementation */
|
||||||
#undef USE_NAMED_POSIX_SEMAPHORES
|
#undef USE_NAMED_POSIX_SEMAPHORES
|
||||||
#undef USE_UNNAMED_POSIX_SEMAPHORES
|
#undef USE_UNNAMED_POSIX_SEMAPHORES
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.86 2003/01/07 22:23:17 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.87 2003/03/06 03:16:55 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -43,6 +43,12 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL_H
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SYS_POLL_H
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SYS_SELECT_H
|
#ifdef HAVE_SYS_SELECT_H
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#endif
|
#endif
|
||||||
@ -55,6 +61,9 @@
|
|||||||
#define DONOTICE(conn,message) \
|
#define DONOTICE(conn,message) \
|
||||||
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
||||||
|
|
||||||
|
static int pqSocketCheck(PGconn *conn, int forRead, int forWrite,
|
||||||
|
time_t end_time);
|
||||||
|
static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time);
|
||||||
static int pqPutBytes(const char *s, size_t nbytes, PGconn *conn);
|
static int pqPutBytes(const char *s, size_t nbytes, PGconn *conn);
|
||||||
|
|
||||||
|
|
||||||
@ -358,40 +367,7 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
|
|||||||
int
|
int
|
||||||
pqReadReady(PGconn *conn)
|
pqReadReady(PGconn *conn)
|
||||||
{
|
{
|
||||||
fd_set input_mask;
|
return pqSocketCheck(conn, 1, 0, (time_t) 0);
|
||||||
struct timeval timeout;
|
|
||||||
|
|
||||||
if (!conn || conn->sock < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* JAB: Check for SSL library buffering read bytes */
|
|
||||||
#ifdef USE_SSL
|
|
||||||
if (conn->ssl && SSL_pending(conn->ssl) > 0)
|
|
||||||
{
|
|
||||||
/* short-circuit the select */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
retry1:
|
|
||||||
FD_ZERO(&input_mask);
|
|
||||||
FD_SET(conn->sock, &input_mask);
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 0;
|
|
||||||
if (select(conn->sock + 1, &input_mask, (fd_set *) NULL, (fd_set *) NULL,
|
|
||||||
&timeout) < 0)
|
|
||||||
{
|
|
||||||
if (SOCK_ERRNO == EINTR)
|
|
||||||
/* Interrupted system call - we'll just try again */
|
|
||||||
goto retry1;
|
|
||||||
|
|
||||||
printfPQExpBuffer(&conn->errorMessage,
|
|
||||||
libpq_gettext("select() failed: %s\n"),
|
|
||||||
SOCK_STRERROR(SOCK_ERRNO));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FD_ISSET(conn->sock, &input_mask) ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -401,30 +377,7 @@ retry1:
|
|||||||
int
|
int
|
||||||
pqWriteReady(PGconn *conn)
|
pqWriteReady(PGconn *conn)
|
||||||
{
|
{
|
||||||
fd_set input_mask;
|
return pqSocketCheck(conn, 0, 1, (time_t) 0);
|
||||||
struct timeval timeout;
|
|
||||||
|
|
||||||
if (!conn || conn->sock < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
retry2:
|
|
||||||
FD_ZERO(&input_mask);
|
|
||||||
FD_SET(conn->sock, &input_mask);
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 0;
|
|
||||||
if (select(conn->sock + 1, (fd_set *) NULL, &input_mask, (fd_set *) NULL,
|
|
||||||
&timeout) < 0)
|
|
||||||
{
|
|
||||||
if (SOCK_ERRNO == EINTR)
|
|
||||||
/* Interrupted system call - we'll just try again */
|
|
||||||
goto retry2;
|
|
||||||
|
|
||||||
printfPQExpBuffer(&conn->errorMessage,
|
|
||||||
libpq_gettext("select() failed: %s\n"),
|
|
||||||
SOCK_STRERROR(SOCK_ERRNO));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return FD_ISSET(conn->sock, &input_mask) ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
@ -785,27 +738,51 @@ pqWait(int forRead, int forWrite, PGconn *conn)
|
|||||||
/*
|
/*
|
||||||
* pqWaitTimed: wait, but not past finish_time.
|
* pqWaitTimed: wait, but not past finish_time.
|
||||||
*
|
*
|
||||||
* If finish_time is exceeded then we return failure (EOF). This is different
|
* If finish_time is exceeded then we return failure (EOF). This is like
|
||||||
* from the response for a kernel exception (return 0) because we don't want
|
* the response for a kernel exception because we don't want the caller
|
||||||
* the caller to try to read/write in that case.
|
* to try to read/write in that case.
|
||||||
*
|
*
|
||||||
* finish_time = ((time_t) -1) disables the wait limit.
|
* finish_time = ((time_t) -1) disables the wait limit.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time)
|
pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time)
|
||||||
{
|
{
|
||||||
fd_set input_mask;
|
int result;
|
||||||
fd_set output_mask;
|
|
||||||
fd_set except_mask;
|
|
||||||
struct timeval tmp_timeout;
|
|
||||||
struct timeval *ptmp_timeout = NULL;
|
|
||||||
int selresult;
|
|
||||||
|
|
||||||
|
result = pqSocketCheck(conn, forRead, forWrite, finish_time);
|
||||||
|
|
||||||
|
if (result < 0)
|
||||||
|
return EOF; /* errorMessage is already set */
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("timeout expired\n"));
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks a socket, using poll or select, for data to be read, written,
|
||||||
|
* or both. Returns >0 if one or more conditions are met, 0 if it timed
|
||||||
|
* out, -1 if an error occurred.
|
||||||
|
* If SSL is in use, the SSL buffer is checked prior to checking the socket
|
||||||
|
* for read data directly.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (!conn)
|
||||||
|
return -1;
|
||||||
if (conn->sock < 0)
|
if (conn->sock < 0)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(&conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
libpq_gettext("connection not open\n"));
|
libpq_gettext("socket not open\n"));
|
||||||
return EOF;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* JAB: Check for SSL library buffering read bytes */
|
/* JAB: Check for SSL library buffering read bytes */
|
||||||
@ -813,62 +790,114 @@ pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time)
|
|||||||
if (forRead && conn->ssl && SSL_pending(conn->ssl) > 0)
|
if (forRead && conn->ssl && SSL_pending(conn->ssl) > 0)
|
||||||
{
|
{
|
||||||
/* short-circuit the select */
|
/* short-circuit the select */
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (forRead || forWrite)
|
/* We will retry as long as we get EINTR */
|
||||||
|
do
|
||||||
{
|
{
|
||||||
retry5:
|
result = pqSocketPoll(conn->sock, forRead, forWrite, end_time);
|
||||||
FD_ZERO(&input_mask);
|
}
|
||||||
FD_ZERO(&output_mask);
|
while (result < 0 && SOCK_ERRNO == EINTR);
|
||||||
FD_ZERO(&except_mask);
|
|
||||||
if (forRead)
|
|
||||||
FD_SET(conn->sock, &input_mask);
|
|
||||||
if (forWrite)
|
|
||||||
FD_SET(conn->sock, &output_mask);
|
|
||||||
FD_SET(conn->sock, &except_mask);
|
|
||||||
|
|
||||||
if (finish_time != ((time_t) -1))
|
if (result < 0)
|
||||||
{
|
{
|
||||||
/*
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
* Set up delay. Assume caller incremented finish_time
|
libpq_gettext("select() failed: %s\n"),
|
||||||
* so that we can error out as soon as time() passes it.
|
SOCK_STRERROR(SOCK_ERRNO));
|
||||||
* Note we will recalculate delay each time through the loop.
|
|
||||||
*/
|
|
||||||
time_t now = time(NULL);
|
|
||||||
|
|
||||||
if (finish_time > now)
|
|
||||||
tmp_timeout.tv_sec = finish_time - now;
|
|
||||||
else
|
|
||||||
tmp_timeout.tv_sec = 0;
|
|
||||||
tmp_timeout.tv_usec = 0;
|
|
||||||
ptmp_timeout = &tmp_timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
selresult = select(conn->sock + 1, &input_mask, &output_mask,
|
|
||||||
&except_mask, ptmp_timeout);
|
|
||||||
if (selresult < 0)
|
|
||||||
{
|
|
||||||
if (SOCK_ERRNO == EINTR)
|
|
||||||
goto retry5;
|
|
||||||
printfPQExpBuffer(&conn->errorMessage,
|
|
||||||
libpq_gettext("select() failed: %s\n"),
|
|
||||||
SOCK_STRERROR(SOCK_ERRNO));
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
if (selresult == 0)
|
|
||||||
{
|
|
||||||
printfPQExpBuffer(&conn->errorMessage,
|
|
||||||
libpq_gettext("timeout expired\n"));
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check a file descriptor for read and/or write data, possibly waiting.
|
||||||
|
* If neither forRead nor forWrite are set, immediately return a timeout
|
||||||
|
* condition (without waiting). Return >0 if condition is met, 0
|
||||||
|
* if a timeout occurred, -1 if an error or interrupt occurred.
|
||||||
|
* Timeout is infinite if end_time is -1. Timeout is immediate (no blocking)
|
||||||
|
* if end_time is 0 (or indeed, any time before now).
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
|
||||||
|
{
|
||||||
|
/* We use poll(2) if available, otherwise select(2) */
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
struct pollfd input_fd;
|
||||||
|
int timeout_ms;
|
||||||
|
|
||||||
|
input_fd.fd = sock;
|
||||||
|
input_fd.events = 0;
|
||||||
|
input_fd.revents = 0;
|
||||||
|
|
||||||
|
if (forRead)
|
||||||
|
input_fd.events |= POLLIN;
|
||||||
|
if (forWrite)
|
||||||
|
input_fd.events |= POLLOUT;
|
||||||
|
if (!input_fd.events)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Compute appropriate timeout interval */
|
||||||
|
if (end_time == ((time_t) -1))
|
||||||
|
{
|
||||||
|
timeout_ms = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
|
if (end_time > now)
|
||||||
|
timeout_ms = (end_time - now) * 1000;
|
||||||
|
else
|
||||||
|
timeout_ms = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return poll(&input_fd, 1, timeout_ms);
|
||||||
|
|
||||||
|
#else /* !HAVE_POLL */
|
||||||
|
|
||||||
|
fd_set input_mask;
|
||||||
|
fd_set output_mask;
|
||||||
|
fd_set except_mask;
|
||||||
|
struct timeval timeout;
|
||||||
|
struct timeval *ptr_timeout;
|
||||||
|
|
||||||
|
if (!forRead && !forWrite)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FD_ZERO(&input_mask);
|
||||||
|
FD_ZERO(&output_mask);
|
||||||
|
FD_ZERO(&except_mask);
|
||||||
|
if (forRead)
|
||||||
|
FD_SET(sock, &input_mask);
|
||||||
|
if (forWrite)
|
||||||
|
FD_SET(sock, &output_mask);
|
||||||
|
FD_SET(sock, &except_mask);
|
||||||
|
|
||||||
|
/* Compute appropriate timeout interval */
|
||||||
|
if (end_time == ((time_t) -1))
|
||||||
|
{
|
||||||
|
ptr_timeout = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
|
if (end_time > now)
|
||||||
|
timeout.tv_sec = end_time - now;
|
||||||
|
else
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
ptr_timeout = &timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
return select(sock + 1, &input_mask, &output_mask,
|
||||||
|
&except_mask, ptr_timeout);
|
||||||
|
#endif /* HAVE_POLL */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A couple of "miscellaneous" multibyte related functions. They used
|
* A couple of "miscellaneous" multibyte related functions. They used
|
||||||
@ -902,6 +931,7 @@ PQenv2encoding(void)
|
|||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_NLS
|
#ifdef ENABLE_NLS
|
||||||
|
|
||||||
char *
|
char *
|
||||||
libpq_gettext(const char *msgid)
|
libpq_gettext(const char *msgid)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user