diff --git a/src/interfaces/libpq/Makefile.in b/src/interfaces/libpq/Makefile.in index 1276f550a2..99da195830 100644 --- a/src/interfaces/libpq/Makefile.in +++ b/src/interfaces/libpq/Makefile.in @@ -6,7 +6,7 @@ # Copyright (c) 1994, Regents of the University of California # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/interfaces/libpq/Attic/Makefile.in,v 1.51 2000/01/10 15:41:30 momjian Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/libpq/Attic/Makefile.in,v 1.52 2000/01/17 02:59:46 tgl Exp $ # #------------------------------------------------------------------------- @@ -28,7 +28,7 @@ CFLAGS+= $(MBFLAGS) endif OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \ - pqexpbuffer.o dllist.o pqsignal.o + pqexpbuffer.o dllist.o pqsignal.o @SNPRINTF@ ifdef MULTIBYTE OBJS+= common.o wchar.o conv.o big5.o @@ -42,14 +42,19 @@ SHLIB_LINK+= $(findstring -lcrypt,$(LIBS)) include $(SRCDIR)/Makefile.shlib -# We need to compile this with special options for shared libs, -# so we can't use the object in $(SRCDIR)/backend +# We use several backend modules verbatim, but since we need to compile +# with appropriate options to build a shared lib, we can't necessarily +# use the same object files as the backend uses. Instead, symlink the +# source files in here and build our own object file. + dllist.c: $(SRCDIR)/backend/lib/dllist.c -$(LN_S) $(SRCDIR)/backend/lib/dllist.c . +# this only gets done if configure finds system doesn't have snprintf() +snprintf.c: $(SRCDIR)/backend/port/snprintf.c + -$(LN_S) $(SRCDIR)/backend/port/snprintf.c . + ifdef MULTIBYTE -# We need to compile this with special options for shared libs, -# so we can't use the object in $(SRCDIR)/backend common.c: $(SRCDIR)/backend/utils/mb/common.c -$(LN_S) $(SRCDIR)/backend/utils/mb/common.c . @@ -63,6 +68,7 @@ big5.c: $(SRCDIR)/backend/utils/mb/big5.c -$(LN_S) $(SRCDIR)/backend/utils/mb/big5.c . endif + # The following rules cause dependencies in the backend directory to # get made if they don't exist, but don't cause them to get remade if they # are out of date. @@ -87,7 +93,7 @@ install-headers: libpq-fe.h libpq-int.h clean: clean-shlib rm -f lib$(NAME).a $(OBJS) - rm -f dllist.c common.c wchar.c conv.c big5.c + rm -f dllist.c snprintf.c common.c wchar.c conv.c big5.c depend dep: $(CC) -MM $(CFLAGS) *.c >depend diff --git a/src/interfaces/libpq/pqexpbuffer.c b/src/interfaces/libpq/pqexpbuffer.c index ddaca7e67b..bedf456b3c 100644 --- a/src/interfaces/libpq/pqexpbuffer.c +++ b/src/interfaces/libpq/pqexpbuffer.c @@ -8,11 +8,15 @@ * * 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(), elog(), nor vsnprintf(). + * 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. * * Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.1 1999/08/31 01:37:37 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.2 2000/01/17 02:59:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -148,27 +152,47 @@ enlargePQExpBuffer(PQExpBuffer str, int needed) * 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(). - * - * CAUTION: the frontend version of this routine WILL FAIL if the result of - * the sprintf formatting operation exceeds 1KB of data (but the size of the - * pre-existing string in the buffer doesn't matter). We could make it - * support larger strings, but that requires vsnprintf() which is not - * universally available. Currently there is no need for long strings to be - * formatted in the frontend. We could support it, if necessary, by - * conditionally including a vsnprintf emulation. */ void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) { va_list args; - char buffer[1024]; - - va_start(args, fmt); - vsprintf(buffer, fmt, args); - va_end(args); + int avail, + nprinted; resetPQExpBuffer(str); - appendPQExpBufferStr(str, buffer); + + for (;;) + { + /*---------- + * Try to format the given string into the available space; + * but if there's hardly any space, don't bother trying, + * just fall through to enlarge the buffer first. + *---------- + */ + avail = str->maxlen - str->len - 1; + if (avail > 16) + { + va_start(args, fmt); + nprinted = vsnprintf(str->data + str->len, avail, + fmt, args); + va_end(args); + /* + * Note: some versions of vsnprintf return the number of chars + * actually stored, but at least one returns -1 on failure. + * Be conservative about believing whether the print worked. + */ + if (nprinted >= 0 && nprinted < avail-1) + { + /* Success. Note nprinted does not include trailing null. */ + str->len += nprinted; + break; + } + } + /* Double the buffer size and try again. */ + if (! enlargePQExpBuffer(str, str->maxlen)) + return; /* oops, out of memory */ + } } /*------------------------ @@ -178,26 +202,45 @@ printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) * 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. - * - * CAUTION: the frontend version of this routine WILL FAIL if the result of - * the sprintf formatting operation exceeds 1KB of data (but the size of the - * pre-existing string in the buffer doesn't matter). We could make it - * support larger strings, but that requires vsnprintf() which is not - * universally available. Currently there is no need for long strings to be - * formatted in the frontend. We could support it, if necessary, by - * conditionally including a vsnprintf emulation. */ void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) { va_list args; - char buffer[1024]; + int avail, + nprinted; - va_start(args, fmt); - vsprintf(buffer, fmt, args); - va_end(args); - - appendPQExpBufferStr(str, buffer); + for (;;) + { + /*---------- + * Try to format the given string into the available space; + * but if there's hardly any space, don't bother trying, + * just fall through to enlarge the buffer first. + *---------- + */ + avail = str->maxlen - str->len - 1; + if (avail > 16) + { + va_start(args, fmt); + nprinted = vsnprintf(str->data + str->len, avail, + fmt, args); + va_end(args); + /* + * Note: some versions of vsnprintf return the number of chars + * actually stored, but at least one returns -1 on failure. + * Be conservative about believing whether the print worked. + */ + if (nprinted >= 0 && nprinted < avail-1) + { + /* Success. Note nprinted does not include trailing null. */ + str->len += nprinted; + break; + } + } + /* Double the buffer size and try again. */ + if (! enlargePQExpBuffer(str, str->maxlen)) + return; /* oops, out of memory */ + } } /*------------------------ diff --git a/src/interfaces/libpq/pqexpbuffer.h b/src/interfaces/libpq/pqexpbuffer.h index 5c2d2f122c..df3566820a 100644 --- a/src/interfaces/libpq/pqexpbuffer.h +++ b/src/interfaces/libpq/pqexpbuffer.h @@ -9,11 +9,15 @@ * * 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(), elog(), nor vsnprintf(). + * 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. * * Copyright (c) 1994, Regents of the University of California * - * $Id: pqexpbuffer.h,v 1.1 1999/08/31 01:37:37 tgl Exp $ + * $Id: pqexpbuffer.h,v 1.2 2000/01/17 02:59:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -116,14 +120,6 @@ extern int enlargePQExpBuffer(PQExpBuffer str, int needed); * 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(). - * - * CAUTION: the frontend version of this routine WILL FAIL if the result of - * the sprintf formatting operation exceeds 1KB of data (but the size of the - * pre-existing string in the buffer doesn't matter). We could make it - * support larger strings, but that requires vsnprintf() which is not - * universally available. Currently there is no need for long strings to be - * formatted in the frontend. We could support it, if necessary, by - * conditionally including a vsnprintf emulation. */ extern void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...); @@ -133,14 +129,6 @@ extern void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...); * 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. - * - * CAUTION: the frontend version of this routine WILL FAIL if the result of - * the sprintf formatting operation exceeds 1KB of data (but the size of the - * pre-existing string in the buffer doesn't matter). We could make it - * support larger strings, but that requires vsnprintf() which is not - * universally available. Currently there is no need for long strings to be - * formatted in the frontend. We could support it, if necessary, by - * conditionally including a vsnprintf emulation. */ extern void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...);