Make StringInfo available to frontend code.
authorAndres Freund <andres@anarazel.de>
Tue, 5 Nov 2019 22:56:40 +0000 (14:56 -0800)
committerAndres Freund <andres@anarazel.de>
Tue, 5 Nov 2019 22:56:40 +0000 (14:56 -0800)
There's plenty places in frontend code that could benefit from a
string buffer implementation. Some because it yields simpler and
faster code, and some others because of the desire to share code
between backend and frontend.

While there is a string buffer implementation available to frontend
code, libpq's PQExpBuffer, it is clunkier than stringinfo, it
introduces a libpq dependency, doesn't allow for sharing between
frontend and backend code, and has a higher API/ABI stability
requirement due to being exposed via libpq.

Therefore it seems best to just making StringInfo being usable by
frontend code. There's not much to do for that, except for rewriting
two subsequent elog/ereport calls into others types of error
reporting, and deciding on a maximum string length.

For the maximum string size I decided to privately define MaxAllocSize
to the same value as used in the backend. It seems likely that we'll
want to reconsider this for both backend and frontend code in the not
too far away future.

For now I've left stringinfo.h in lib/, rather than common/, to reduce
the likelihood of unnecessary breakage. We could alternatively decide
to provide a redirecting stringinfo.h in lib/, or just not provide
compatibility.

Author: Andres Freund
Reviewed-By: Kyotaro Horiguchi, Daniel Gustafsson
Discussion: https://postgr.es/m/20190920051857.2fhnvhvx4qdddviz@alap3.anarazel.de

src/backend/lib/Makefile
src/bin/pg_waldump/compat.c
src/bin/pg_waldump/pg_waldump.c
src/common/Makefile
src/common/stringinfo.c [moved from src/backend/lib/stringinfo.c with 86% similarity]
src/include/lib/stringinfo.h
src/tools/msvc/Mkvcbuild.pm

index dbea67bc379d20366b31f997bade4a7bcbc61e0f..9dad31398aed0ef927e07ca25969d9793069f4d7 100644 (file)
@@ -23,6 +23,5 @@ OBJS = \
    knapsack.o \
    pairingheap.o \
    rbtree.o \
-   stringinfo.o
 
 include $(top_srcdir)/src/backend/common.mk
index 7b389a20c965b98b5b7b78620111ad7303b9020e..5db83880fb78a163a764e374450292d845724339 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <time.h>
 
-#include "lib/stringinfo.h"
 #include "utils/datetime.h"
 
 /* copied from timestamp.c */
@@ -63,29 +62,3 @@ timestamptz_to_str(TimestampTz dt)
 
    return buf;
 }
-
-/*
- * Provide a hacked up compat layer for StringInfos so xlog desc functions can
- * be linked/called.
- */
-void
-appendStringInfo(StringInfo str, const char *fmt,...)
-{
-   va_list     args;
-
-   va_start(args, fmt);
-   vprintf(fmt, args);
-   va_end(args);
-}
-
-void
-appendStringInfoString(StringInfo str, const char *string)
-{
-   appendStringInfo(str, "%s", string);
-}
-
-void
-appendStringInfoChar(StringInfo str, char ch)
-{
-   appendStringInfo(str, "%c", ch);
-}
index 8e4bff6aa3c6ce30e921f64d45dfa25cc1ff1fc6..1524e5eb1ef5528e71df77abd8ddd5da87f46627 100644 (file)
@@ -514,6 +514,7 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record)
    int         block_id;
    uint8       info = XLogRecGetInfo(record);
    XLogRecPtr  xl_prev = XLogRecGetPrev(record);
+   StringInfoData s;
 
    XLogDumpRecordLen(record, &rec_len, &fpi_len);
 
@@ -530,8 +531,10 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record)
    else
        printf("desc: %s ", id);
 
-   /* the desc routine will printf the description directly to stdout */
-   desc->rm_desc(NULL, record);
+   initStringInfo(&s);
+   desc->rm_desc(&s, record);
+   printf("%s", s.data);
+   pfree(s.data);
 
    if (!config->bkp_details)
    {
index 4fd487a4ec4f25e42948547cc13fbfa467ef2e73..ffb0f6edffa11ec94bdc18c112ea34a462f3ccd8 100644 (file)
@@ -67,6 +67,7 @@ OBJS_COMMON = \
    saslprep.o \
    scram-common.o \
    string.o \
+   stringinfo.o \
    unicode_norm.o \
    username.o \
    wait_error.o
similarity index 86%
rename from src/backend/lib/stringinfo.c
rename to src/common/stringinfo.c
index 99c83c1549c5c2873ba966516bd9a2474e22f102..a50e587da90c847b0c556ab1667262a73cb4dc98 100644 (file)
@@ -2,21 +2,34 @@
  *
  * stringinfo.c
  *
- * StringInfo 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 palloc().
+ * StringInfo provides an extensible string data type (currently limited to a
+ * length of 1GB).  It can be used to buffer either ordinary C strings
+ * (null-terminated text) or arbitrary binary data.  All storage is allocated
+ * with palloc() (falling back to malloc in frontend code).
  *
  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *   src/backend/lib/stringinfo.c
+ *   src/common/stringinfo.c
  *
  *-------------------------------------------------------------------------
  */
+
+#ifndef FRONTEND
+
 #include "postgres.h"
+#include "utils/memutils.h"
+
+#else
+
+#include "postgres_fe.h"
+
+/* It's possible we could use a different value for this in frontend code */
+#define MaxAllocSize   ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
+
+#endif
 
 #include "lib/stringinfo.h"
-#include "utils/memutils.h"
 
 
 /*
@@ -261,10 +274,10 @@ appendBinaryStringInfoNT(StringInfo str, const char *data, int datalen)
  * can save some palloc overhead by enlarging the buffer before starting
  * to store data in it.
  *
- * NB: because we use repalloc() to enlarge the buffer, the string buffer
- * will remain allocated in the same memory context that was current when
- * initStringInfo was called, even if another context is now current.
- * This is the desired and indeed critical behavior!
+ * NB: In the backend, because we use repalloc() to enlarge the buffer, the
+ * string buffer will remain allocated in the same memory context that was
+ * current when initStringInfo was called, even if another context is now
+ * current.  This is the desired and indeed critical behavior!
  */
 void
 enlargeStringInfo(StringInfo str, int needed)
@@ -276,13 +289,29 @@ enlargeStringInfo(StringInfo str, int needed)
     * an overflow or infinite loop in the following.
     */
    if (needed < 0)             /* should not happen */
+   {
+#ifndef FRONTEND
        elog(ERROR, "invalid string enlargement request size: %d", needed);
+#else
+       fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
+       exit(EXIT_FAILURE);
+#endif
+   }
    if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
+   {
+#ifndef FRONTEND
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("out of memory"),
                 errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
                           str->len, needed)));
+#else
+       fprintf(stderr,
+               _("out of memory\n\nCannot enlarge string buffer containing %d bytes by %d more bytes.\n"),
+               str->len, needed);
+       exit(EXIT_FAILURE);
+#endif
+   }
 
    needed += str->len + 1;     /* total space required now */
 
index c4842778c51a5158ade33f88d18edeccdc0d4a0c..e27942728e7d78ed8ffec616e515dac8fc77e5d9 100644 (file)
@@ -3,9 +3,10 @@
  * stringinfo.h
  *   Declarations/definitions for "StringInfo" functions.
  *
- * StringInfo 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 palloc().
+ * StringInfo provides an extensible string data type (currently limited to a
+ * length of 1GB).  It can be used to buffer either ordinary C strings
+ * (null-terminated text) or arbitrary binary data.  All storage is allocated
+ * with palloc() (falling back to malloc in frontend code).
  *
  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
index 7a103e61406e53e691ffea2dea760e59be5257d6..9a0963a050d97c16a8744ddadf5bf371defb3440 100644 (file)
@@ -123,7 +123,7 @@ sub mkvcbuild
      base64.c config_info.c controldata_utils.c d2s.c exec.c f2s.c file_perm.c ip.c
      keywords.c kwlookup.c link-canary.c md5.c
      pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
-     saslprep.c scram-common.c string.c unicode_norm.c username.c
+     saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c
      wait_error.c);
 
    if ($solution->{options}->{openssl})