Create src/fe_utils/, and move stuff into there from pg_dump's dumputils.
authorTom Lane
Thu, 24 Mar 2016 19:55:44 +0000 (15:55 -0400)
committerTom Lane
Thu, 24 Mar 2016 19:55:57 +0000 (15:55 -0400)
Per discussion, we want to create a static library and put the stuff into
it that until now has been shared across src/bin/ directories by ad-hoc
methods like symlinking a source file.  This commit creates the library and
populates it with a couple of files that contain the widely-useful portions
of pg_dump's dumputils.c file.  dumputils.c survives, because it has some
stuff that didn't seem appropriate for fe_utils, but it's significantly
smaller and is no longer referenced from any other directory.

Follow-on patches will move more stuff into fe_utils.

The Mkvcbuild.pm hacking here is just a best guess; we'll see how the
buildfarm likes it.

35 files changed:
src/Makefile
src/Makefile.global.in
src/bin/pg_dump/Makefile
src/bin/pg_dump/common.c
src/bin/pg_dump/dumputils.c
src/bin/pg_dump/dumputils.h
src/bin/pg_dump/parallel.c
src/bin/pg_dump/pg_backup.h
src/bin/pg_dump/pg_backup_archiver.c
src/bin/pg_dump/pg_backup_null.c
src/bin/pg_dump/pg_backup_tar.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/pg_dump/pg_dumpall.c
src/bin/psql/.gitignore
src/bin/psql/Makefile
src/bin/psql/command.c
src/bin/psql/copy.c
src/bin/psql/describe.c
src/bin/scripts/.gitignore
src/bin/scripts/Makefile
src/bin/scripts/clusterdb.c
src/bin/scripts/createdb.c
src/bin/scripts/createuser.c
src/bin/scripts/dropdb.c
src/bin/scripts/dropuser.c
src/bin/scripts/reindexdb.c
src/bin/scripts/vacuumdb.c
src/fe_utils/Makefile [new file with mode: 0644]
src/fe_utils/simple_list.c [new file with mode: 0644]
src/fe_utils/string_utils.c [new file with mode: 0644]
src/include/Makefile
src/include/fe_utils/simple_list.h [new file with mode: 0644]
src/include/fe_utils/string_utils.h [new file with mode: 0644]
src/tools/msvc/Mkvcbuild.pm

index e859826dc4fd66888f3f0f49e01f4d48ce4bd68b..b526be798596b4da3472d0701ac2133600f4b059 100644 (file)
@@ -22,6 +22,7 @@ SUBDIRS = \
    include \
    interfaces \
    backend/replication/libpqwalreceiver \
+   fe_utils \
    bin \
    pl \
    makefiles \
index 47b265ee498321e8c6dfc81f792909fba5eb9fba..811d05f4608bda11d69c7f15b111649a74a0d02b 100644 (file)
@@ -501,7 +501,12 @@ submake-libpgport:
    $(MAKE) -C $(top_builddir)/src/port all
    $(MAKE) -C $(top_builddir)/src/common all
 
-.PHONY: submake-libpq submake-libpgport
+submake-libpgfeutils:
+   $(MAKE) -C $(top_builddir)/src/port all
+   $(MAKE) -C $(top_builddir)/src/common all
+   $(MAKE) -C $(top_builddir)/src/fe_utils all
+
+.PHONY: submake-libpq submake-libpgport submake-libpgfeutils
 
 
 ##########################################################################
index ddf940210ab1513626e1165cdad6448b616688b5..ea515fd9de4e155468005082e3b466de3332c6f5 100644 (file)
@@ -17,6 +17,7 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
+LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils
 
 OBJS=  pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
    pg_backup_null.o pg_backup_tar.o pg_backup_directory.o \
@@ -24,13 +25,13 @@ OBJS=   pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
 
 all: pg_dump pg_restore pg_dumpall
 
-pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) | submake-libpq submake-libpgport
+pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
    $(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
-pg_restore: pg_restore.o $(OBJS) | submake-libpq submake-libpgport
+pg_restore: pg_restore.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
    $(CC) $(CFLAGS) pg_restore.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
-pg_dumpall: pg_dumpall.o dumputils.o | submake-libpq submake-libpgport
+pg_dumpall: pg_dumpall.o dumputils.o | submake-libpq submake-libpgport submake-libpgfeutils
    $(CC) $(CFLAGS) pg_dumpall.o dumputils.o $(WIN32RES) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
index 1acd91ab4449208185aa6924975cbcbbf43607f0..373d3bc54b17eb3d52f322b1bf384ffc3dd40132 100644 (file)
@@ -22,6 +22,7 @@
 #include 
 
 #include "catalog/pg_class.h"
+#include "fe_utils/string_utils.h"
 
 
 /*
@@ -992,37 +993,3 @@ strInArray(const char *pattern, char **arr, int arr_size)
    }
    return -1;
 }
-
-
-/*
- * Support for simple list operations
- */
-
-void
-simple_oid_list_append(SimpleOidList *list, Oid val)
-{
-   SimpleOidListCell *cell;
-
-   cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
-   cell->next = NULL;
-   cell->val = val;
-
-   if (list->tail)
-       list->tail->next = cell;
-   else
-       list->head = cell;
-   list->tail = cell;
-}
-
-bool
-simple_oid_list_member(SimpleOidList *list, Oid val)
-{
-   SimpleOidListCell *cell;
-
-   for (cell = list->head; cell; cell = cell->next)
-   {
-       if (cell->val == val)
-           return true;
-   }
-   return false;
-}
index a685d28d6009dc063e67cc523579e38c305c1745..5301d3fa54193d1102b6b6ba5404ab365aac25dc 100644 (file)
@@ -1,8 +1,8 @@
 /*-------------------------------------------------------------------------
  *
  * Utility routines for SQL dumping
- * Basically this is stuff that is useful in both pg_dump and pg_dumpall.
- * Lately it's also being used by psql and bin/scripts/ ...
+ *
+ * Basically this is stuff that is useful in both pg_dump and pg_dumpall.
  *
  *
  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  */
 #include "postgres_fe.h"
 
-#include 
-
 #include "dumputils.h"
-
-#include "common/keywords.h"
+#include "fe_utils/string_utils.h"
 
 
 #define supports_grant_options(version) ((version) >= 70400)
@@ -30,441 +27,6 @@ static bool parseAclItem(const char *item, const char *type,
 static char *copyAclUserName(PQExpBuffer output, char *input);
 static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
       const char *subname);
-static PQExpBuffer defaultGetLocalPQExpBuffer(void);
-
-/* Globals exported by this file */
-int            quote_all_identifiers = 0;
-PQExpBuffer (*getLocalPQExpBuffer) (void) = defaultGetLocalPQExpBuffer;
-
-/*
- * Returns a temporary PQExpBuffer, valid until the next call to the function.
- * This is used by fmtId and fmtQualifiedId.
- *
- * Non-reentrant and non-thread-safe but reduces memory leakage. You can
- * replace this with a custom version by setting the getLocalPQExpBuffer
- * function pointer.
- */
-static PQExpBuffer
-defaultGetLocalPQExpBuffer(void)
-{
-   static PQExpBuffer id_return = NULL;
-
-   if (id_return)              /* first time through? */
-   {
-       /* same buffer, just wipe contents */
-       resetPQExpBuffer(id_return);
-   }
-   else
-   {
-       /* new buffer */
-       id_return = createPQExpBuffer();
-   }
-
-   return id_return;
-}
-
-/*
- * Quotes input string if it's not a legitimate SQL identifier as-is.
- *
- * Note that the returned string must be used before calling fmtId again,
- * since we re-use the same return buffer each time.
- */
-const char *
-fmtId(const char *rawid)
-{
-   PQExpBuffer id_return = getLocalPQExpBuffer();
-
-   const char *cp;
-   bool        need_quotes = false;
-
-   /*
-    * These checks need to match the identifier production in scan.l. Don't
-    * use islower() etc.
-    */
-   if (quote_all_identifiers)
-       need_quotes = true;
-   /* slightly different rules for first character */
-   else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
-       need_quotes = true;
-   else
-   {
-       /* otherwise check the entire string */
-       for (cp = rawid; *cp; cp++)
-       {
-           if (!((*cp >= 'a' && *cp <= 'z')
-                 || (*cp >= '0' && *cp <= '9')
-                 || (*cp == '_')))
-           {
-               need_quotes = true;
-               break;
-           }
-       }
-   }
-
-   if (!need_quotes)
-   {
-       /*
-        * Check for keyword.  We quote keywords except for unreserved ones.
-        * (In some cases we could avoid quoting a col_name or type_func_name
-        * keyword, but it seems much harder than it's worth to tell that.)
-        *
-        * Note: ScanKeywordLookup() does case-insensitive comparison, but
-        * that's fine, since we already know we have all-lower-case.
-        */
-       const ScanKeyword *keyword = ScanKeywordLookup(rawid,
-                                                      ScanKeywords,
-                                                      NumScanKeywords);
-
-       if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
-           need_quotes = true;
-   }
-
-   if (!need_quotes)
-   {
-       /* no quoting needed */
-       appendPQExpBufferStr(id_return, rawid);
-   }
-   else
-   {
-       appendPQExpBufferChar(id_return, '"');
-       for (cp = rawid; *cp; cp++)
-       {
-           /*
-            * Did we find a double-quote in the string? Then make this a
-            * double double-quote per SQL99. Before, we put in a
-            * backslash/double-quote pair. - thomas 2000-08-05
-            */
-           if (*cp == '"')
-               appendPQExpBufferChar(id_return, '"');
-           appendPQExpBufferChar(id_return, *cp);
-       }
-       appendPQExpBufferChar(id_return, '"');
-   }
-
-   return id_return->data;
-}
-
-/*
- * fmtQualifiedId - convert a qualified name to the proper format for
- * the source database.
- *
- * Like fmtId, use the result before calling again.
- *
- * Since we call fmtId and it also uses getThreadLocalPQExpBuffer() we cannot
- * use it until we're finished with calling fmtId().
- */
-const char *
-fmtQualifiedId(int remoteVersion, const char *schema, const char *id)
-{
-   PQExpBuffer id_return;
-   PQExpBuffer lcl_pqexp = createPQExpBuffer();
-
-   /* Suppress schema name if fetching from pre-7.3 DB */
-   if (remoteVersion >= 70300 && schema && *schema)
-   {
-       appendPQExpBuffer(lcl_pqexp, "%s.", fmtId(schema));
-   }
-   appendPQExpBufferStr(lcl_pqexp, fmtId(id));
-
-   id_return = getLocalPQExpBuffer();
-
-   appendPQExpBufferStr(id_return, lcl_pqexp->data);
-   destroyPQExpBuffer(lcl_pqexp);
-
-   return id_return->data;
-}
-
-/*
- * Convert a string value to an SQL string literal and append it to
- * the given buffer.  We assume the specified client_encoding and
- * standard_conforming_strings settings.
- *
- * This is essentially equivalent to libpq's PQescapeStringInternal,
- * except for the output buffer structure.  We need it in situations
- * where we do not have a PGconn available.  Where we do,
- * appendStringLiteralConn is a better choice.
- */
-void
-appendStringLiteral(PQExpBuffer buf, const char *str,
-                   int encoding, bool std_strings)
-{
-   size_t      length = strlen(str);
-   const char *source = str;
-   char       *target;
-
-   if (!enlargePQExpBuffer(buf, 2 * length + 2))
-       return;
-
-   target = buf->data + buf->len;
-   *target++ = '\'';
-
-   while (*source != '\0')
-   {
-       char        c = *source;
-       int         len;
-       int         i;
-
-       /* Fast path for plain ASCII */
-       if (!IS_HIGHBIT_SET(c))
-       {
-           /* Apply quoting if needed */
-           if (SQL_STR_DOUBLE(c, !std_strings))
-               *target++ = c;
-           /* Copy the character */
-           *target++ = c;
-           source++;
-           continue;
-       }
-
-       /* Slow path for possible multibyte characters */
-       len = PQmblen(source, encoding);
-
-       /* Copy the character */
-       for (i = 0; i < len; i++)
-       {
-           if (*source == '\0')
-               break;
-           *target++ = *source++;
-       }
-
-       /*
-        * If we hit premature end of string (ie, incomplete multibyte
-        * character), try to pad out to the correct length with spaces. We
-        * may not be able to pad completely, but we will always be able to
-        * insert at least one pad space (since we'd not have quoted a
-        * multibyte character).  This should be enough to make a string that
-        * the server will error out on.
-        */
-       if (i < len)
-       {
-           char       *stop = buf->data + buf->maxlen - 2;
-
-           for (; i < len; i++)
-           {
-               if (target >= stop)
-                   break;
-               *target++ = ' ';
-           }
-           break;
-       }
-   }
-
-   /* Write the terminating quote and NUL character. */
-   *target++ = '\'';
-   *target = '\0';
-
-   buf->len = target - buf->data;
-}
-
-
-/*
- * Convert a string value to an SQL string literal and append it to
- * the given buffer.  Encoding and string syntax rules are as indicated
- * by current settings of the PGconn.
- */
-void
-appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
-{
-   size_t      length = strlen(str);
-
-   /*
-    * XXX This is a kluge to silence escape_string_warning in our utility
-    * programs.  It should go away someday.
-    */
-   if (strchr(str, '\\') != NULL && PQserverVersion(conn) >= 80100)
-   {
-       /* ensure we are not adjacent to an identifier */
-       if (buf->len > 0 && buf->data[buf->len - 1] != ' ')
-           appendPQExpBufferChar(buf, ' ');
-       appendPQExpBufferChar(buf, ESCAPE_STRING_SYNTAX);
-       appendStringLiteral(buf, str, PQclientEncoding(conn), false);
-       return;
-   }
-   /* XXX end kluge */
-
-   if (!enlargePQExpBuffer(buf, 2 * length + 2))
-       return;
-   appendPQExpBufferChar(buf, '\'');
-   buf->len += PQescapeStringConn(conn, buf->data + buf->len,
-                                  str, length, NULL);
-   appendPQExpBufferChar(buf, '\'');
-}
-
-
-/*
- * Convert a string value to a dollar quoted literal and append it to
- * the given buffer. If the dqprefix parameter is not NULL then the
- * dollar quote delimiter will begin with that (after the opening $).
- *
- * No escaping is done at all on str, in compliance with the rules
- * for parsing dollar quoted strings.  Also, we need not worry about
- * encoding issues.
- */
-void
-appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
-{
-   static const char suffixes[] = "_XXXXXXX";
-   int         nextchar = 0;
-   PQExpBuffer delimBuf = createPQExpBuffer();
-
-   /* start with $ + dqprefix if not NULL */
-   appendPQExpBufferChar(delimBuf, '$');
-   if (dqprefix)
-       appendPQExpBufferStr(delimBuf, dqprefix);
-
-   /*
-    * Make sure we choose a delimiter which (without the trailing $) is not
-    * present in the string being quoted. We don't check with the trailing $
-    * because a string ending in $foo must not be quoted with $foo$.
-    */
-   while (strstr(str, delimBuf->data) != NULL)
-   {
-       appendPQExpBufferChar(delimBuf, suffixes[nextchar++]);
-       nextchar %= sizeof(suffixes) - 1;
-   }
-
-   /* add trailing $ */
-   appendPQExpBufferChar(delimBuf, '$');
-
-   /* quote it and we are all done */
-   appendPQExpBufferStr(buf, delimBuf->data);
-   appendPQExpBufferStr(buf, str);
-   appendPQExpBufferStr(buf, delimBuf->data);
-
-   destroyPQExpBuffer(delimBuf);
-}
-
-
-/*
- * Convert a bytea value (presented as raw bytes) to an SQL string literal
- * and append it to the given buffer.  We assume the specified
- * standard_conforming_strings setting.
- *
- * This is needed in situations where we do not have a PGconn available.
- * Where we do, PQescapeByteaConn is a better choice.
- */
-void
-appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
-                  bool std_strings)
-{
-   const unsigned char *source = str;
-   char       *target;
-
-   static const char hextbl[] = "0123456789abcdef";
-
-   /*
-    * This implementation is hard-wired to produce hex-format output. We do
-    * not know the server version the output will be loaded into, so making
-    * an intelligent format choice is impossible.  It might be better to
-    * always use the old escaped format.
-    */
-   if (!enlargePQExpBuffer(buf, 2 * length + 5))
-       return;
-
-   target = buf->data + buf->len;
-   *target++ = '\'';
-   if (!std_strings)
-       *target++ = '\\';
-   *target++ = '\\';
-   *target++ = 'x';
-
-   while (length-- > 0)
-   {
-       unsigned char c = *source++;
-
-       *target++ = hextbl[(c >> 4) & 0xF];
-       *target++ = hextbl[c & 0xF];
-   }
-
-   /* Write the terminating quote and NUL character. */
-   *target++ = '\'';
-   *target = '\0';
-
-   buf->len = target - buf->data;
-}
-
-
-/*
- * Deconstruct the text representation of a 1-dimensional Postgres array
- * into individual items.
- *
- * On success, returns true and sets *itemarray and *nitems to describe
- * an array of individual strings.  On parse failure, returns false;
- * *itemarray may exist or be NULL.
- *
- * NOTE: free'ing itemarray is sufficient to deallocate the working storage.
- */
-bool
-parsePGArray(const char *atext, char ***itemarray, int *nitems)
-{
-   int         inputlen;
-   char      **items;
-   char       *strings;
-   int         curitem;
-
-   /*
-    * We expect input in the form of "{item,item,item}" where any item is
-    * either raw data, or surrounded by double quotes (in which case embedded
-    * characters including backslashes and quotes are backslashed).
-    *
-    * We build the result as an array of pointers followed by the actual
-    * string data, all in one malloc block for convenience of deallocation.
-    * The worst-case storage need is not more than one pointer and one
-    * character for each input character (consider "{,,,,,,,,,,}").
-    */
-   *itemarray = NULL;
-   *nitems = 0;
-   inputlen = strlen(atext);
-   if (inputlen < 2 || atext[0] != '{' || atext[inputlen - 1] != '}')
-       return false;           /* bad input */
-   items = (char **) malloc(inputlen * (sizeof(char *) + sizeof(char)));
-   if (items == NULL)
-       return false;           /* out of memory */
-   *itemarray = items;
-   strings = (char *) (items + inputlen);
-
-   atext++;                    /* advance over initial '{' */
-   curitem = 0;
-   while (*atext != '}')
-   {
-       if (*atext == '\0')
-           return false;       /* premature end of string */
-       items[curitem] = strings;
-       while (*atext != '}' && *atext != ',')
-       {
-           if (*atext == '\0')
-               return false;   /* premature end of string */
-           if (*atext != '"')
-               *strings++ = *atext++;  /* copy unquoted data */
-           else
-           {
-               /* process quoted substring */
-               atext++;
-               while (*atext != '"')
-               {
-                   if (*atext == '\0')
-                       return false;   /* premature end of string */
-                   if (*atext == '\\')
-                   {
-                       atext++;
-                       if (*atext == '\0')
-                           return false;       /* premature end of string */
-                   }
-                   *strings++ = *atext++;      /* copy quoted data */
-               }
-               atext++;
-           }
-       }
-       *strings++ = '\0';
-       if (*atext == ',')
-           atext++;
-       curitem++;
-   }
-   if (atext[1] != '\0')
-       return false;           /* bogus syntax (embedded '}') */
-   *nitems = curitem;
-   return true;
-}
 
 
 /*
@@ -950,218 +512,6 @@ AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname)
 }
 
 
-/*
- * processSQLNamePattern
- *
- * Scan a wildcard-pattern string and generate appropriate WHERE clauses
- * to limit the set of objects returned.  The WHERE clauses are appended
- * to the already-partially-constructed query in buf.  Returns whether
- * any clause was added.
- *
- * conn: connection query will be sent to (consulted for escaping rules).
- * buf: output parameter.
- * pattern: user-specified pattern option, or NULL if none ("*" is implied).
- * have_where: true if caller already emitted "WHERE" (clauses will be ANDed
- * onto the existing WHERE clause).
- * force_escape: always quote regexp special characters, even outside
- * double quotes (else they are quoted only between double quotes).
- * schemavar: name of query variable to match against a schema-name pattern.
- * Can be NULL if no schema.
- * namevar: name of query variable to match against an object-name pattern.
- * altnamevar: NULL, or name of an alternative variable to match against name.
- * visibilityrule: clause to use if we want to restrict to visible objects
- * (for example, "pg_catalog.pg_table_is_visible(p.oid)").  Can be NULL.
- *
- * Formatting note: the text already present in buf should end with a newline.
- * The appended text, if any, will end with one too.
- */
-bool
-processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
-                     bool have_where, bool force_escape,
-                     const char *schemavar, const char *namevar,
-                     const char *altnamevar, const char *visibilityrule)
-{
-   PQExpBufferData schemabuf;
-   PQExpBufferData namebuf;
-   int         encoding = PQclientEncoding(conn);
-   bool        inquotes;
-   const char *cp;
-   int         i;
-   bool        added_clause = false;
-
-#define WHEREAND() \
-   (appendPQExpBufferStr(buf, have_where ? "  AND " : "WHERE "), \
-    have_where = true, added_clause = true)
-
-   if (pattern == NULL)
-   {
-       /* Default: select all visible objects */
-       if (visibilityrule)
-       {
-           WHEREAND();
-           appendPQExpBuffer(buf, "%s\n", visibilityrule);
-       }
-       return added_clause;
-   }
-
-   initPQExpBuffer(&schemabuf);
-   initPQExpBuffer(&namebuf);
-
-   /*
-    * Parse the pattern, converting quotes and lower-casing unquoted letters.
-    * Also, adjust shell-style wildcard characters into regexp notation.
-    *
-    * We surround the pattern with "^(...)$" to force it to match the whole
-    * string, as per SQL practice.  We have to have parens in case the string
-    * contains "|", else the "^" and "$" will be bound into the first and
-    * last alternatives which is not what we want.
-    *
-    * Note: the result of this pass is the actual regexp pattern(s) we want
-    * to execute.  Quoting/escaping into SQL literal format will be done
-    * below using appendStringLiteralConn().
-    */
-   appendPQExpBufferStr(&namebuf, "^(");
-
-   inquotes = false;
-   cp = pattern;
-
-   while (*cp)
-   {
-       char        ch = *cp;
-
-       if (ch == '"')
-       {
-           if (inquotes && cp[1] == '"')
-           {
-               /* emit one quote, stay in inquotes mode */
-               appendPQExpBufferChar(&namebuf, '"');
-               cp++;
-           }
-           else
-               inquotes = !inquotes;
-           cp++;
-       }
-       else if (!inquotes && isupper((unsigned char) ch))
-       {
-           appendPQExpBufferChar(&namebuf,
-                                 pg_tolower((unsigned char) ch));
-           cp++;
-       }
-       else if (!inquotes && ch == '*')
-       {
-           appendPQExpBufferStr(&namebuf, ".*");
-           cp++;
-       }
-       else if (!inquotes && ch == '?')
-       {
-           appendPQExpBufferChar(&namebuf, '.');
-           cp++;
-       }
-       else if (!inquotes && ch == '.')
-       {
-           /* Found schema/name separator, move current pattern to schema */
-           resetPQExpBuffer(&schemabuf);
-           appendPQExpBufferStr(&schemabuf, namebuf.data);
-           resetPQExpBuffer(&namebuf);
-           appendPQExpBufferStr(&namebuf, "^(");
-           cp++;
-       }
-       else if (ch == '$')
-       {
-           /*
-            * Dollar is always quoted, whether inside quotes or not. The
-            * reason is that it's allowed in SQL identifiers, so there's a
-            * significant use-case for treating it literally, while because
-            * we anchor the pattern automatically there is no use-case for
-            * having it possess its regexp meaning.
-            */
-           appendPQExpBufferStr(&namebuf, "\\$");
-           cp++;
-       }
-       else
-       {
-           /*
-            * Ordinary data character, transfer to pattern
-            *
-            * Inside double quotes, or at all times if force_escape is true,
-            * quote regexp special characters with a backslash to avoid
-            * regexp errors.  Outside quotes, however, let them pass through
-            * as-is; this lets knowledgeable users build regexp expressions
-            * that are more powerful than shell-style patterns.
-            */
-           if ((inquotes || force_escape) &&
-               strchr("|*+?()[]{}.^$\\", ch))
-               appendPQExpBufferChar(&namebuf, '\\');
-           i = PQmblen(cp, encoding);
-           while (i-- && *cp)
-           {
-               appendPQExpBufferChar(&namebuf, *cp);
-               cp++;
-           }
-       }
-   }
-
-   /*
-    * Now decide what we need to emit.  Note there will be a leading "^(" in
-    * the patterns in any case.
-    */
-   if (namebuf.len > 2)
-   {
-       /* We have a name pattern, so constrain the namevar(s) */
-
-       appendPQExpBufferStr(&namebuf, ")$");
-       /* Optimize away a "*" pattern */
-       if (strcmp(namebuf.data, "^(.*)$") != 0)
-       {
-           WHEREAND();
-           if (altnamevar)
-           {
-               appendPQExpBuffer(buf, "(%s ~ ", namevar);
-               appendStringLiteralConn(buf, namebuf.data, conn);
-               appendPQExpBuffer(buf, "\n        OR %s ~ ", altnamevar);
-               appendStringLiteralConn(buf, namebuf.data, conn);
-               appendPQExpBufferStr(buf, ")\n");
-           }
-           else
-           {
-               appendPQExpBuffer(buf, "%s ~ ", namevar);
-               appendStringLiteralConn(buf, namebuf.data, conn);
-               appendPQExpBufferChar(buf, '\n');
-           }
-       }
-   }
-
-   if (schemabuf.len > 2)
-   {
-       /* We have a schema pattern, so constrain the schemavar */
-
-       appendPQExpBufferStr(&schemabuf, ")$");
-       /* Optimize away a "*" pattern */
-       if (strcmp(schemabuf.data, "^(.*)$") != 0 && schemavar)
-       {
-           WHEREAND();
-           appendPQExpBuffer(buf, "%s ~ ", schemavar);
-           appendStringLiteralConn(buf, schemabuf.data, conn);
-           appendPQExpBufferChar(buf, '\n');
-       }
-   }
-   else
-   {
-       /* No schema pattern given, so select only visible objects */
-       if (visibilityrule)
-       {
-           WHEREAND();
-           appendPQExpBuffer(buf, "%s\n", visibilityrule);
-       }
-   }
-
-   termPQExpBuffer(&schemabuf);
-   termPQExpBuffer(&namebuf);
-
-   return added_clause;
-#undef WHEREAND
-}
-
 /*
  * buildShSecLabelQuery
  *
@@ -1205,52 +555,3 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
        appendPQExpBufferStr(buffer, ";\n");
    }
 }
-
-
-void
-simple_string_list_append(SimpleStringList *list, const char *val)
-{
-   SimpleStringListCell *cell;
-
-   cell = (SimpleStringListCell *)
-       pg_malloc(offsetof(SimpleStringListCell, val) +strlen(val) + 1);
-
-   cell->next = NULL;
-   cell->touched = false;
-   strcpy(cell->val, val);
-
-   if (list->tail)
-       list->tail->next = cell;
-   else
-       list->head = cell;
-   list->tail = cell;
-}
-
-bool
-simple_string_list_member(SimpleStringList *list, const char *val)
-{
-   SimpleStringListCell *cell;
-
-   for (cell = list->head; cell; cell = cell->next)
-   {
-       if (strcmp(cell->val, val) == 0)
-       {
-           cell->touched = true;
-           return true;
-       }
-   }
-   return false;
-}
-
-const char *
-simple_string_list_not_touched(SimpleStringList *list)
-{
-   SimpleStringListCell *cell;
-
-   for (cell = list->head; cell; cell = cell->next)
-   {
-       if (!cell->touched)
-           return cell->val;
-   }
-   return NULL;
-}
index 4941ec02e7956fc1fe70801aea743cac7794d8a2..4b404be99a90898a77ea7e447f49f2a8307e8bac 100644 (file)
@@ -1,8 +1,8 @@
 /*-------------------------------------------------------------------------
  *
  * Utility routines for SQL dumping
- * Basically this is stuff that is useful in both pg_dump and pg_dumpall.
- * Lately it's also being used by psql and bin/scripts/ ...
+ *
+ * Basically this is stuff that is useful in both pg_dump and pg_dumpall.
  *
  *
  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
 #include "libpq-fe.h"
 #include "pqexpbuffer.h"
 
-/*
- * Data structures for simple lists of OIDs and strings.  The support for
- * these is very primitive compared to the backend's List facilities, but
- * it's all we need in pg_dump.
- */
-typedef struct SimpleOidListCell
-{
-   struct SimpleOidListCell *next;
-   Oid         val;
-} SimpleOidListCell;
-
-typedef struct SimpleOidList
-{
-   SimpleOidListCell *head;
-   SimpleOidListCell *tail;
-} SimpleOidList;
-
-typedef struct SimpleStringListCell
-{
-   struct SimpleStringListCell *next;
-   bool        touched;        /* true, when this string was searched and
-                                * touched */
-   char        val[FLEXIBLE_ARRAY_MEMBER];     /* null-terminated string here */
-} SimpleStringListCell;
-
-typedef struct SimpleStringList
-{
-   SimpleStringListCell *head;
-   SimpleStringListCell *tail;
-} SimpleStringList;
-
-#define atooid(x)  ((Oid) strtoul((x), NULL, 10))
-
 /*
  * Preferred strftime(3) format specifier for printing timestamps in pg_dump
  * and friends.
@@ -68,22 +35,7 @@ typedef struct SimpleStringList
 #define PGDUMP_STRFTIME_FMT  "%Y-%m-%d %H:%M:%S"
 #endif
 
-extern int quote_all_identifiers;
-extern PQExpBuffer (*getLocalPQExpBuffer) (void);
 
-extern const char *fmtId(const char *identifier);
-extern const char *fmtQualifiedId(int remoteVersion,
-              const char *schema, const char *id);
-extern void appendStringLiteral(PQExpBuffer buf, const char *str,
-                   int encoding, bool std_strings);
-extern void appendStringLiteralConn(PQExpBuffer buf, const char *str,
-                       PGconn *conn);
-extern void appendStringLiteralDQ(PQExpBuffer buf, const char *str,
-                     const char *dqprefix);
-extern void appendByteaLiteral(PQExpBuffer buf,
-                  const unsigned char *str, size_t length,
-                  bool std_strings);
-extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
 extern bool buildACLCommands(const char *name, const char *subname,
                 const char *type, const char *acls, const char *owner,
                 const char *prefix, int remoteVersion,
@@ -92,20 +44,9 @@ extern bool buildDefaultACLCommands(const char *type, const char *nspname,
                        const char *acls, const char *owner,
                        int remoteVersion,
                        PQExpBuffer sql);
-extern bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf,
-                     const char *pattern,
-                     bool have_where, bool force_escape,
-                     const char *schemavar, const char *namevar,
-                     const char *altnamevar, const char *visibilityrule);
 extern void buildShSecLabelQuery(PGconn *conn, const char *catalog_name,
                     uint32 objectId, PQExpBuffer sql);
 extern void emitShSecLabels(PGconn *conn, PGresult *res,
                PQExpBuffer buffer, const char *target, const char *objname);
-extern void set_dump_section(const char *arg, int *dumpSections);
-
-extern void simple_string_list_append(SimpleStringList *list, const char *val);
-extern bool simple_string_list_member(SimpleStringList *list, const char *val);
-extern const char *simple_string_list_not_touched(SimpleStringList *list);
-
 
 #endif   /* DUMPUTILS_H */
index 9ce7711bf4d950d6d4ab5b33f112b68011613532..91672949e69480e78cad980f9cb2acadfad1d6b4 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "parallel.h"
 #include "pg_backup_utils.h"
+#include "fe_utils/string_utils.h"
 
 #ifndef WIN32
 #include 
index 26061e7a6ec72c9d238c130e8df7b3a6a48f3e67..83f6029c1fea6ec0111156d504095bf088652790 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef PG_BACKUP_H
 #define PG_BACKUP_H
 
-#include "dumputils.h"
+#include "fe_utils/simple_list.h"
 #include "libpq-fe.h"
 
 
index 0132dad0a212a8d40386b1cd1884086cd9b3f429..fdca64f07ef78dcf586885cbbf2ff60a82e188e5 100644 (file)
@@ -25,6 +25,8 @@
 #include "pg_backup_archiver.h"
 #include "pg_backup_db.h"
 #include "pg_backup_utils.h"
+#include "dumputils.h"
+#include "fe_utils/string_utils.h"
 
 #include 
 #include 
index 848eed49d0d91015beebf46233d8e77a2a2c5eed..ff419bb82f468e24f655b2b56668e3233aecc98b 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "pg_backup_archiver.h"
 #include "pg_backup_utils.h"
+#include "fe_utils/string_utils.h"
 
 #include "libpq/libpq-fs.h"
 
index eb5bcbb0e31adc4702699dc2a8db06828fb65412..8dfc6a98de1117e62c74654a72aa18c394efe36b 100644 (file)
@@ -33,6 +33,7 @@
 #include "pg_backup_tar.h"
 #include "pg_backup_utils.h"
 #include "pgtar.h"
+#include "fe_utils/string_utils.h"
 
 #include 
 #include 
index b3ef201a3ae2e45b78a493d8e6922284c54f8e73..ad4b4e5135e7e5746f2a0462cbcf891d05175e39 100644 (file)
@@ -61,6 +61,7 @@
 #include "pg_backup_db.h"
 #include "pg_backup_utils.h"
 #include "pg_dump.h"
+#include "fe_utils/string_utils.h"
 
 
 typedef struct
index 66e693183ae40ef2d7806eb517745e82fcb1db0a..c02c536a9c4d6b5b9f48b07b4debd7ad2c2f8298 100644 (file)
@@ -536,9 +536,6 @@ extern ExtensionInfo *findExtensionByOid(Oid oid);
 extern void setExtensionMembership(ExtensionMemberId *extmems, int nextmems);
 extern ExtensionInfo *findOwningExtension(CatalogId catalogId);
 
-extern void simple_oid_list_append(SimpleOidList *list, Oid val);
-extern bool simple_oid_list_member(SimpleOidList *list, Oid val);
-
 extern void parseOidArray(const char *str, Oid *array, int arraysize);
 
 extern void sortDumpableObjects(DumpableObject **objs, int numObjs,
index be6b4a898e758be40bfb19b6fc514d1064291fd7..530d3f4d2c07a9ecc19911f7e6359c8861ae59a9 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "dumputils.h"
 #include "pg_backup.h"
+#include "fe_utils/string_utils.h"
 
 /* version string we expect back from pg_dump */
 #define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
index ce881f45ad25b4d4ed5403847b3d83c3d6966048..9de50c0a287006e622c492abe5713bb6403656b6 100644 (file)
@@ -2,6 +2,5 @@
 /psqlscanslash.c
 /sql_help.h
 /sql_help.c
-/dumputils.c
 
 /psql
index 75a9b395b4a13609f7d5594ad83c3b580f4f8799..251d638990096828e81fbf9fd21899ac516a0434 100644 (file)
@@ -18,25 +18,23 @@ include $(top_builddir)/src/Makefile.global
 
 REFDOCDIR= $(top_srcdir)/doc/src/sgml/ref
 
-override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) -I$(top_srcdir)/src/bin/pg_dump $(CPPFLAGS)
+override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS)
+LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils
 
 OBJS=  command.o common.o help.o input.o stringutils.o mainloop.o copy.o \
    startup.o prompt.o variables.o large_obj.o print.o describe.o \
-   tab-complete.o mbprint.o dumputils.o \
+   tab-complete.o mbprint.o \
    sql_help.o psqlscan.o psqlscanslash.o \
    $(WIN32RES)
 
 
 all: psql
 
-psql: $(OBJS) | submake-libpq submake-libpgport
+psql: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
    $(CC) $(CFLAGS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 help.o: sql_help.h
 
-dumputils.c: % : $(top_srcdir)/src/bin/pg_dump/%
-   rm -f $@ && $(LN_S) $< .
-
 sql_help.c: sql_help.h ;
 sql_help.h: create_help.pl $(wildcard $(REFDOCDIR)/*.sgml)
    $(PERL) $< $(REFDOCDIR) $*
@@ -67,7 +65,7 @@ uninstall:
    rm -f '$(DESTDIR)$(bindir)/psql$(X)' '$(DESTDIR)$(datadir)/psqlrc.sample'
 
 clean distclean:
-   rm -f psql$(X) $(OBJS) dumputils.c lex.backup
+   rm -f psql$(X) $(OBJS) lex.backup
 
 # files removed here are supposed to be in the distribution tarball,
 # so do not clean them in the clean/distclean rules
index 3ea12b8f8f955f17c10ce64ed22eb51db2c72190..e5ec8af11c56120ed1e9c69d6c4c630ed220ab32 100644 (file)
@@ -35,7 +35,7 @@
 
 #include "libpq-fe.h"
 #include "pqexpbuffer.h"
-#include "dumputils.h"
+#include "fe_utils/string_utils.h"
 
 #include "common.h"
 #include "copy.h"
index ff1d61b568f3cc235ccbaf375c4f7420314d314a..942264fbf976ca3b5d690ff5fb0ac190833bd7e3 100644 (file)
@@ -18,7 +18,6 @@
 
 #include "libpq-fe.h"
 #include "pqexpbuffer.h"
-#include "dumputils.h"
 
 #include "settings.h"
 #include "common.h"
index fd8dc9122d464878a9771e63ceffcad627234cdd..b824d4e54929e3ce2024803eadbc0eb8326f7979 100644 (file)
 #include 
 
 #include "catalog/pg_default_acl.h"
+#include "fe_utils/string_utils.h"
 
 #include "common.h"
 #include "describe.h"
-#include "dumputils.h"
 #include "mbprint.h"
 #include "print.h"
 #include "settings.h"
index e12d27a2f1b08a989f61c46575671b52538c3a41..784f25b93e7760ca901490214ada978e7290f0c6 100644 (file)
@@ -9,7 +9,6 @@
 /vacuumdb
 /pg_isready
 
-/dumputils.c
 /mbprint.c
 /print.c
 
index ad34d42d682364250ed7b710b6d1a66c0310cae1..5e47e13a78a98fcf56d589420b947d391bdab7f9 100644 (file)
@@ -18,27 +18,25 @@ include $(top_builddir)/src/Makefile.global
 
 PROGRAMS = createdb createlang createuser dropdb droplang dropuser clusterdb vacuumdb reindexdb pg_isready
 
-override CPPFLAGS := -I$(top_srcdir)/src/bin/pg_dump -I$(top_srcdir)/src/bin/psql -I$(libpq_srcdir) $(CPPFLAGS)
+override CPPFLAGS := -I$(top_srcdir)/src/bin/psql -I$(libpq_srcdir) $(CPPFLAGS)
+LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils
 
 all: $(PROGRAMS)
 
 %: %.o $(WIN32RES)
    $(CC) $(CFLAGS) $^ $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
-createdb: createdb.o common.o dumputils.o | submake-libpq submake-libpgport
+createdb: createdb.o common.o | submake-libpq submake-libpgport submake-libpgfeutils
 createlang: createlang.o common.o print.o mbprint.o | submake-libpq submake-libpgport
-createuser: createuser.o common.o dumputils.o | submake-libpq submake-libpgport
-dropdb: dropdb.o common.o dumputils.o | submake-libpq submake-libpgport
+createuser: createuser.o common.o | submake-libpq submake-libpgport submake-libpgfeutils
+dropdb: dropdb.o common.o | submake-libpq submake-libpgport submake-libpgfeutils
 droplang: droplang.o common.o print.o mbprint.o | submake-libpq submake-libpgport
-dropuser: dropuser.o common.o dumputils.o | submake-libpq submake-libpgport
-clusterdb: clusterdb.o common.o dumputils.o | submake-libpq submake-libpgport
-vacuumdb: vacuumdb.o common.o dumputils.o | submake-libpq submake-libpgport
-reindexdb: reindexdb.o common.o dumputils.o | submake-libpq submake-libpgport
+dropuser: dropuser.o common.o | submake-libpq submake-libpgport submake-libpgfeutils
+clusterdb: clusterdb.o common.o | submake-libpq submake-libpgport submake-libpgfeutils
+vacuumdb: vacuumdb.o common.o | submake-libpq submake-libpgport submake-libpgfeutils
+reindexdb: reindexdb.o common.o | submake-libpq submake-libpgport submake-libpgfeutils
 pg_isready: pg_isready.o common.o | submake-libpq submake-libpgport
 
-dumputils.c: % : $(top_srcdir)/src/bin/pg_dump/%
-   rm -f $@ && $(LN_S) $< .
-
 print.c mbprint.c : % : $(top_srcdir)/src/bin/psql/%
    rm -f $@ && $(LN_S) $< .
 
@@ -62,8 +60,8 @@ uninstall:
 
 clean distclean maintainer-clean:
    rm -f $(addsuffix $(X), $(PROGRAMS)) $(addsuffix .o, $(PROGRAMS))
-   rm -f common.o dumputils.o print.o mbprint.o $(WIN32RES)
-   rm -f dumputils.c print.c mbprint.c
+   rm -f common.o print.o mbprint.o $(WIN32RES)
+   rm -f print.c mbprint.c
    rm -rf tmp_check
 
 check:
index 9e8d9580a66779d34723bc0182309df48b3c2dfa..be34ba11220a800b4ee9266b60c02cf0d580e427 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "postgres_fe.h"
 #include "common.h"
-#include "dumputils.h"
+#include "fe_utils/simple_list.h"
 
 
 static void cluster_one_database(const char *dbname, bool verbose, const char *table,
index d08b1a77f1e9215ae5d3ff21381ac5918c81a2cc..fddfde76e23bbf7c94db425e4f94e76e26ab3b71 100644 (file)
@@ -12,7 +12,7 @@
 #include "postgres_fe.h"
 
 #include "common.h"
-#include "dumputils.h"
+#include "fe_utils/string_utils.h"
 
 
 static void help(const char *progname);
index 35e48e334f7229087d22ab892d27340dd944626e..e88879dc19e4134a9a98e93f91db2925856dd0f7 100644 (file)
@@ -12,7 +12,8 @@
 
 #include "postgres_fe.h"
 #include "common.h"
-#include "dumputils.h"
+#include "fe_utils/simple_list.h"
+#include "fe_utils/string_utils.h"
 
 
 static void help(const char *progname);
index 08b72a77ba343308023e872f4b2f02b2538df865..145beb02217fea193b3f1903744c8f31570285d8 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "postgres_fe.h"
 #include "common.h"
-#include "dumputils.h"
+#include "fe_utils/string_utils.h"
 
 
 static void help(const char *progname);
index df91eec22c9156c2c292a4277135ff47feb3218f..31fa28f7cdc4cb958f18d9d95d51201557383b14 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "postgres_fe.h"
 #include "common.h"
-#include "dumputils.h"
+#include "fe_utils/string_utils.h"
 
 
 static void help(const char *progname);
index c25bd26675d966e933ae9744d2f60ce24d39a2bd..0c8c90c22a429d56d5c453d37a781429091db9b8 100644 (file)
@@ -11,7 +11,8 @@
 
 #include "postgres_fe.h"
 #include "common.h"
-#include "dumputils.h"
+#include "fe_utils/simple_list.h"
+#include "fe_utils/string_utils.h"
 
 
 static void reindex_one_database(const char *name, const char *dbname,
index b673be83ff16830f170136e81a856b2bd6118866..dbaae1288b8ea5419e5b6faf9667dc7821ddd297 100644 (file)
@@ -13,7 +13,8 @@
 #include "postgres_fe.h"
 
 #include "common.h"
-#include "dumputils.h"
+#include "fe_utils/simple_list.h"
+#include "fe_utils/string_utils.h"
 
 
 #define ERRCODE_UNDEFINED_TABLE  "42P01"
diff --git a/src/fe_utils/Makefile b/src/fe_utils/Makefile
new file mode 100644 (file)
index 0000000..f6a52df
--- /dev/null
@@ -0,0 +1,39 @@
+#-------------------------------------------------------------------------
+#
+# Makefile
+#    Makefile for src/fe_utils
+#
+# This makefile generates a static library, libpgfeutils.a,
+# for use by client applications
+#
+# IDENTIFICATION
+#    src/fe_utils/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/fe_utils
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+
+override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
+
+OBJS = simple_list.o string_utils.o
+
+all: libpgfeutils.a
+
+libpgfeutils.a: $(OBJS)
+   rm -f $@
+   $(AR) $(AROPT) $@ $^
+
+# libpgfeutils could be useful to contrib, so install it
+install: all installdirs
+   $(INSTALL_STLIB) libpgfeutils.a '$(DESTDIR)$(libdir)/libpgfeutils.a'
+
+installdirs:
+   $(MKDIR_P) '$(DESTDIR)$(libdir)'
+
+uninstall:
+   rm -f '$(DESTDIR)$(libdir)/libpgfeutils.a'
+
+clean distclean maintainer-clean:
+   rm -f libpgfeutils.a $(OBJS)
diff --git a/src/fe_utils/simple_list.c b/src/fe_utils/simple_list.c
new file mode 100644 (file)
index 0000000..ed4d188
--- /dev/null
@@ -0,0 +1,116 @@
+/*-------------------------------------------------------------------------
+ *
+ * Simple list facilities for frontend code
+ *
+ * Data structures for simple lists of OIDs and strings.  The support for
+ * these is very primitive compared to the backend's List facilities, but
+ * it's all we need in, eg, pg_dump.
+ *
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/fe_utils/simple_list.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include "fe_utils/simple_list.h"
+
+
+/*
+ * Append an OID to the list.
+ */
+void
+simple_oid_list_append(SimpleOidList *list, Oid val)
+{
+   SimpleOidListCell *cell;
+
+   cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
+   cell->next = NULL;
+   cell->val = val;
+
+   if (list->tail)
+       list->tail->next = cell;
+   else
+       list->head = cell;
+   list->tail = cell;
+}
+
+/*
+ * Is OID present in the list?
+ */
+bool
+simple_oid_list_member(SimpleOidList *list, Oid val)
+{
+   SimpleOidListCell *cell;
+
+   for (cell = list->head; cell; cell = cell->next)
+   {
+       if (cell->val == val)
+           return true;
+   }
+   return false;
+}
+
+/*
+ * Append a string to the list.
+ *
+ * The given string is copied, so it need not survive past the call.
+ */
+void
+simple_string_list_append(SimpleStringList *list, const char *val)
+{
+   SimpleStringListCell *cell;
+
+   cell = (SimpleStringListCell *)
+       pg_malloc(offsetof(SimpleStringListCell, val) +strlen(val) + 1);
+
+   cell->next = NULL;
+   cell->touched = false;
+   strcpy(cell->val, val);
+
+   if (list->tail)
+       list->tail->next = cell;
+   else
+       list->head = cell;
+   list->tail = cell;
+}
+
+/*
+ * Is string present in the list?
+ *
+ * If found, the "touched" field of the first match is set true.
+ */
+bool
+simple_string_list_member(SimpleStringList *list, const char *val)
+{
+   SimpleStringListCell *cell;
+
+   for (cell = list->head; cell; cell = cell->next)
+   {
+       if (strcmp(cell->val, val) == 0)
+       {
+           cell->touched = true;
+           return true;
+       }
+   }
+   return false;
+}
+
+/*
+ * Find first not-touched list entry, if there is one.
+ */
+const char *
+simple_string_list_not_touched(SimpleStringList *list)
+{
+   SimpleStringListCell *cell;
+
+   for (cell = list->head; cell; cell = cell->next)
+   {
+       if (!cell->touched)
+           return cell->val;
+   }
+   return NULL;
+}
diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c
new file mode 100644 (file)
index 0000000..c57d836
--- /dev/null
@@ -0,0 +1,674 @@
+/*-------------------------------------------------------------------------
+ *
+ * String-processing utility routines for frontend code
+ *
+ * Assorted utility functions that are useful in constructing SQL queries
+ * and interpreting backend output.
+ *
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/fe_utils/string_utils.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include 
+
+#include "fe_utils/string_utils.h"
+
+#include "common/keywords.h"
+
+
+static PQExpBuffer defaultGetLocalPQExpBuffer(void);
+
+/* Globals exported by this file */
+int            quote_all_identifiers = 0;
+PQExpBuffer (*getLocalPQExpBuffer) (void) = defaultGetLocalPQExpBuffer;
+
+
+/*
+ * Returns a temporary PQExpBuffer, valid until the next call to the function.
+ * This is used by fmtId and fmtQualifiedId.
+ *
+ * Non-reentrant and non-thread-safe but reduces memory leakage. You can
+ * replace this with a custom version by setting the getLocalPQExpBuffer
+ * function pointer.
+ */
+static PQExpBuffer
+defaultGetLocalPQExpBuffer(void)
+{
+   static PQExpBuffer id_return = NULL;
+
+   if (id_return)              /* first time through? */
+   {
+       /* same buffer, just wipe contents */
+       resetPQExpBuffer(id_return);
+   }
+   else
+   {
+       /* new buffer */
+       id_return = createPQExpBuffer();
+   }
+
+   return id_return;
+}
+
+/*
+ * Quotes input string if it's not a legitimate SQL identifier as-is.
+ *
+ * Note that the returned string must be used before calling fmtId again,
+ * since we re-use the same return buffer each time.
+ */
+const char *
+fmtId(const char *rawid)
+{
+   PQExpBuffer id_return = getLocalPQExpBuffer();
+
+   const char *cp;
+   bool        need_quotes = false;
+
+   /*
+    * These checks need to match the identifier production in scan.l. Don't
+    * use islower() etc.
+    */
+   if (quote_all_identifiers)
+       need_quotes = true;
+   /* slightly different rules for first character */
+   else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
+       need_quotes = true;
+   else
+   {
+       /* otherwise check the entire string */
+       for (cp = rawid; *cp; cp++)
+       {
+           if (!((*cp >= 'a' && *cp <= 'z')
+                 || (*cp >= '0' && *cp <= '9')
+                 || (*cp == '_')))
+           {
+               need_quotes = true;
+               break;
+           }
+       }
+   }
+
+   if (!need_quotes)
+   {
+       /*
+        * Check for keyword.  We quote keywords except for unreserved ones.
+        * (In some cases we could avoid quoting a col_name or type_func_name
+        * keyword, but it seems much harder than it's worth to tell that.)
+        *
+        * Note: ScanKeywordLookup() does case-insensitive comparison, but
+        * that's fine, since we already know we have all-lower-case.
+        */
+       const ScanKeyword *keyword = ScanKeywordLookup(rawid,
+                                                      ScanKeywords,
+                                                      NumScanKeywords);
+
+       if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
+           need_quotes = true;
+   }
+
+   if (!need_quotes)
+   {
+       /* no quoting needed */
+       appendPQExpBufferStr(id_return, rawid);
+   }
+   else
+   {
+       appendPQExpBufferChar(id_return, '"');
+       for (cp = rawid; *cp; cp++)
+       {
+           /*
+            * Did we find a double-quote in the string? Then make this a
+            * double double-quote per SQL99. Before, we put in a
+            * backslash/double-quote pair. - thomas 2000-08-05
+            */
+           if (*cp == '"')
+               appendPQExpBufferChar(id_return, '"');
+           appendPQExpBufferChar(id_return, *cp);
+       }
+       appendPQExpBufferChar(id_return, '"');
+   }
+
+   return id_return->data;
+}
+
+/*
+ * fmtQualifiedId - convert a qualified name to the proper format for
+ * the source database.
+ *
+ * Like fmtId, use the result before calling again.
+ *
+ * Since we call fmtId and it also uses getThreadLocalPQExpBuffer() we cannot
+ * use it until we're finished with calling fmtId().
+ */
+const char *
+fmtQualifiedId(int remoteVersion, const char *schema, const char *id)
+{
+   PQExpBuffer id_return;
+   PQExpBuffer lcl_pqexp = createPQExpBuffer();
+
+   /* Suppress schema name if fetching from pre-7.3 DB */
+   if (remoteVersion >= 70300 && schema && *schema)
+   {
+       appendPQExpBuffer(lcl_pqexp, "%s.", fmtId(schema));
+   }
+   appendPQExpBufferStr(lcl_pqexp, fmtId(id));
+
+   id_return = getLocalPQExpBuffer();
+
+   appendPQExpBufferStr(id_return, lcl_pqexp->data);
+   destroyPQExpBuffer(lcl_pqexp);
+
+   return id_return->data;
+}
+
+
+/*
+ * Convert a string value to an SQL string literal and append it to
+ * the given buffer.  We assume the specified client_encoding and
+ * standard_conforming_strings settings.
+ *
+ * This is essentially equivalent to libpq's PQescapeStringInternal,
+ * except for the output buffer structure.  We need it in situations
+ * where we do not have a PGconn available.  Where we do,
+ * appendStringLiteralConn is a better choice.
+ */
+void
+appendStringLiteral(PQExpBuffer buf, const char *str,
+                   int encoding, bool std_strings)
+{
+   size_t      length = strlen(str);
+   const char *source = str;
+   char       *target;
+
+   if (!enlargePQExpBuffer(buf, 2 * length + 2))
+       return;
+
+   target = buf->data + buf->len;
+   *target++ = '\'';
+
+   while (*source != '\0')
+   {
+       char        c = *source;
+       int         len;
+       int         i;
+
+       /* Fast path for plain ASCII */
+       if (!IS_HIGHBIT_SET(c))
+       {
+           /* Apply quoting if needed */
+           if (SQL_STR_DOUBLE(c, !std_strings))
+               *target++ = c;
+           /* Copy the character */
+           *target++ = c;
+           source++;
+           continue;
+       }
+
+       /* Slow path for possible multibyte characters */
+       len = PQmblen(source, encoding);
+
+       /* Copy the character */
+       for (i = 0; i < len; i++)
+       {
+           if (*source == '\0')
+               break;
+           *target++ = *source++;
+       }
+
+       /*
+        * If we hit premature end of string (ie, incomplete multibyte
+        * character), try to pad out to the correct length with spaces. We
+        * may not be able to pad completely, but we will always be able to
+        * insert at least one pad space (since we'd not have quoted a
+        * multibyte character).  This should be enough to make a string that
+        * the server will error out on.
+        */
+       if (i < len)
+       {
+           char       *stop = buf->data + buf->maxlen - 2;
+
+           for (; i < len; i++)
+           {
+               if (target >= stop)
+                   break;
+               *target++ = ' ';
+           }
+           break;
+       }
+   }
+
+   /* Write the terminating quote and NUL character. */
+   *target++ = '\'';
+   *target = '\0';
+
+   buf->len = target - buf->data;
+}
+
+
+/*
+ * Convert a string value to an SQL string literal and append it to
+ * the given buffer.  Encoding and string syntax rules are as indicated
+ * by current settings of the PGconn.
+ */
+void
+appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
+{
+   size_t      length = strlen(str);
+
+   /*
+    * XXX This is a kluge to silence escape_string_warning in our utility
+    * programs.  It should go away someday.
+    */
+   if (strchr(str, '\\') != NULL && PQserverVersion(conn) >= 80100)
+   {
+       /* ensure we are not adjacent to an identifier */
+       if (buf->len > 0 && buf->data[buf->len - 1] != ' ')
+           appendPQExpBufferChar(buf, ' ');
+       appendPQExpBufferChar(buf, ESCAPE_STRING_SYNTAX);
+       appendStringLiteral(buf, str, PQclientEncoding(conn), false);
+       return;
+   }
+   /* XXX end kluge */
+
+   if (!enlargePQExpBuffer(buf, 2 * length + 2))
+       return;
+   appendPQExpBufferChar(buf, '\'');
+   buf->len += PQescapeStringConn(conn, buf->data + buf->len,
+                                  str, length, NULL);
+   appendPQExpBufferChar(buf, '\'');
+}
+
+
+/*
+ * Convert a string value to a dollar quoted literal and append it to
+ * the given buffer. If the dqprefix parameter is not NULL then the
+ * dollar quote delimiter will begin with that (after the opening $).
+ *
+ * No escaping is done at all on str, in compliance with the rules
+ * for parsing dollar quoted strings.  Also, we need not worry about
+ * encoding issues.
+ */
+void
+appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
+{
+   static const char suffixes[] = "_XXXXXXX";
+   int         nextchar = 0;
+   PQExpBuffer delimBuf = createPQExpBuffer();
+
+   /* start with $ + dqprefix if not NULL */
+   appendPQExpBufferChar(delimBuf, '$');
+   if (dqprefix)
+       appendPQExpBufferStr(delimBuf, dqprefix);
+
+   /*
+    * Make sure we choose a delimiter which (without the trailing $) is not
+    * present in the string being quoted. We don't check with the trailing $
+    * because a string ending in $foo must not be quoted with $foo$.
+    */
+   while (strstr(str, delimBuf->data) != NULL)
+   {
+       appendPQExpBufferChar(delimBuf, suffixes[nextchar++]);
+       nextchar %= sizeof(suffixes) - 1;
+   }
+
+   /* add trailing $ */
+   appendPQExpBufferChar(delimBuf, '$');
+
+   /* quote it and we are all done */
+   appendPQExpBufferStr(buf, delimBuf->data);
+   appendPQExpBufferStr(buf, str);
+   appendPQExpBufferStr(buf, delimBuf->data);
+
+   destroyPQExpBuffer(delimBuf);
+}
+
+
+/*
+ * Convert a bytea value (presented as raw bytes) to an SQL string literal
+ * and append it to the given buffer.  We assume the specified
+ * standard_conforming_strings setting.
+ *
+ * This is needed in situations where we do not have a PGconn available.
+ * Where we do, PQescapeByteaConn is a better choice.
+ */
+void
+appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
+                  bool std_strings)
+{
+   const unsigned char *source = str;
+   char       *target;
+
+   static const char hextbl[] = "0123456789abcdef";
+
+   /*
+    * This implementation is hard-wired to produce hex-format output. We do
+    * not know the server version the output will be loaded into, so making
+    * an intelligent format choice is impossible.  It might be better to
+    * always use the old escaped format.
+    */
+   if (!enlargePQExpBuffer(buf, 2 * length + 5))
+       return;
+
+   target = buf->data + buf->len;
+   *target++ = '\'';
+   if (!std_strings)
+       *target++ = '\\';
+   *target++ = '\\';
+   *target++ = 'x';
+
+   while (length-- > 0)
+   {
+       unsigned char c = *source++;
+
+       *target++ = hextbl[(c >> 4) & 0xF];
+       *target++ = hextbl[c & 0xF];
+   }
+
+   /* Write the terminating quote and NUL character. */
+   *target++ = '\'';
+   *target = '\0';
+
+   buf->len = target - buf->data;
+}
+
+
+/*
+ * Deconstruct the text representation of a 1-dimensional Postgres array
+ * into individual items.
+ *
+ * On success, returns true and sets *itemarray and *nitems to describe
+ * an array of individual strings.  On parse failure, returns false;
+ * *itemarray may exist or be NULL.
+ *
+ * NOTE: free'ing itemarray is sufficient to deallocate the working storage.
+ */
+bool
+parsePGArray(const char *atext, char ***itemarray, int *nitems)
+{
+   int         inputlen;
+   char      **items;
+   char       *strings;
+   int         curitem;
+
+   /*
+    * We expect input in the form of "{item,item,item}" where any item is
+    * either raw data, or surrounded by double quotes (in which case embedded
+    * characters including backslashes and quotes are backslashed).
+    *
+    * We build the result as an array of pointers followed by the actual
+    * string data, all in one malloc block for convenience of deallocation.
+    * The worst-case storage need is not more than one pointer and one
+    * character for each input character (consider "{,,,,,,,,,,}").
+    */
+   *itemarray = NULL;
+   *nitems = 0;
+   inputlen = strlen(atext);
+   if (inputlen < 2 || atext[0] != '{' || atext[inputlen - 1] != '}')
+       return false;           /* bad input */
+   items = (char **) malloc(inputlen * (sizeof(char *) + sizeof(char)));
+   if (items == NULL)
+       return false;           /* out of memory */
+   *itemarray = items;
+   strings = (char *) (items + inputlen);
+
+   atext++;                    /* advance over initial '{' */
+   curitem = 0;
+   while (*atext != '}')
+   {
+       if (*atext == '\0')
+           return false;       /* premature end of string */
+       items[curitem] = strings;
+       while (*atext != '}' && *atext != ',')
+       {
+           if (*atext == '\0')
+               return false;   /* premature end of string */
+           if (*atext != '"')
+               *strings++ = *atext++;  /* copy unquoted data */
+           else
+           {
+               /* process quoted substring */
+               atext++;
+               while (*atext != '"')
+               {
+                   if (*atext == '\0')
+                       return false;   /* premature end of string */
+                   if (*atext == '\\')
+                   {
+                       atext++;
+                       if (*atext == '\0')
+                           return false;       /* premature end of string */
+                   }
+                   *strings++ = *atext++;      /* copy quoted data */
+               }
+               atext++;
+           }
+       }
+       *strings++ = '\0';
+       if (*atext == ',')
+           atext++;
+       curitem++;
+   }
+   if (atext[1] != '\0')
+       return false;           /* bogus syntax (embedded '}') */
+   *nitems = curitem;
+   return true;
+}
+
+
+/*
+ * processSQLNamePattern
+ *
+ * Scan a wildcard-pattern string and generate appropriate WHERE clauses
+ * to limit the set of objects returned.  The WHERE clauses are appended
+ * to the already-partially-constructed query in buf.  Returns whether
+ * any clause was added.
+ *
+ * conn: connection query will be sent to (consulted for escaping rules).
+ * buf: output parameter.
+ * pattern: user-specified pattern option, or NULL if none ("*" is implied).
+ * have_where: true if caller already emitted "WHERE" (clauses will be ANDed
+ * onto the existing WHERE clause).
+ * force_escape: always quote regexp special characters, even outside
+ * double quotes (else they are quoted only between double quotes).
+ * schemavar: name of query variable to match against a schema-name pattern.
+ * Can be NULL if no schema.
+ * namevar: name of query variable to match against an object-name pattern.
+ * altnamevar: NULL, or name of an alternative variable to match against name.
+ * visibilityrule: clause to use if we want to restrict to visible objects
+ * (for example, "pg_catalog.pg_table_is_visible(p.oid)").  Can be NULL.
+ *
+ * Formatting note: the text already present in buf should end with a newline.
+ * The appended text, if any, will end with one too.
+ */
+bool
+processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
+                     bool have_where, bool force_escape,
+                     const char *schemavar, const char *namevar,
+                     const char *altnamevar, const char *visibilityrule)
+{
+   PQExpBufferData schemabuf;
+   PQExpBufferData namebuf;
+   int         encoding = PQclientEncoding(conn);
+   bool        inquotes;
+   const char *cp;
+   int         i;
+   bool        added_clause = false;
+
+#define WHEREAND() \
+   (appendPQExpBufferStr(buf, have_where ? "  AND " : "WHERE "), \
+    have_where = true, added_clause = true)
+
+   if (pattern == NULL)
+   {
+       /* Default: select all visible objects */
+       if (visibilityrule)
+       {
+           WHEREAND();
+           appendPQExpBuffer(buf, "%s\n", visibilityrule);
+       }
+       return added_clause;
+   }
+
+   initPQExpBuffer(&schemabuf);
+   initPQExpBuffer(&namebuf);
+
+   /*
+    * Parse the pattern, converting quotes and lower-casing unquoted letters.
+    * Also, adjust shell-style wildcard characters into regexp notation.
+    *
+    * We surround the pattern with "^(...)$" to force it to match the whole
+    * string, as per SQL practice.  We have to have parens in case the string
+    * contains "|", else the "^" and "$" will be bound into the first and
+    * last alternatives which is not what we want.
+    *
+    * Note: the result of this pass is the actual regexp pattern(s) we want
+    * to execute.  Quoting/escaping into SQL literal format will be done
+    * below using appendStringLiteralConn().
+    */
+   appendPQExpBufferStr(&namebuf, "^(");
+
+   inquotes = false;
+   cp = pattern;
+
+   while (*cp)
+   {
+       char        ch = *cp;
+
+       if (ch == '"')
+       {
+           if (inquotes && cp[1] == '"')
+           {
+               /* emit one quote, stay in inquotes mode */
+               appendPQExpBufferChar(&namebuf, '"');
+               cp++;
+           }
+           else
+               inquotes = !inquotes;
+           cp++;
+       }
+       else if (!inquotes && isupper((unsigned char) ch))
+       {
+           appendPQExpBufferChar(&namebuf,
+                                 pg_tolower((unsigned char) ch));
+           cp++;
+       }
+       else if (!inquotes && ch == '*')
+       {
+           appendPQExpBufferStr(&namebuf, ".*");
+           cp++;
+       }
+       else if (!inquotes && ch == '?')
+       {
+           appendPQExpBufferChar(&namebuf, '.');
+           cp++;
+       }
+       else if (!inquotes && ch == '.')
+       {
+           /* Found schema/name separator, move current pattern to schema */
+           resetPQExpBuffer(&schemabuf);
+           appendPQExpBufferStr(&schemabuf, namebuf.data);
+           resetPQExpBuffer(&namebuf);
+           appendPQExpBufferStr(&namebuf, "^(");
+           cp++;
+       }
+       else if (ch == '$')
+       {
+           /*
+            * Dollar is always quoted, whether inside quotes or not. The
+            * reason is that it's allowed in SQL identifiers, so there's a
+            * significant use-case for treating it literally, while because
+            * we anchor the pattern automatically there is no use-case for
+            * having it possess its regexp meaning.
+            */
+           appendPQExpBufferStr(&namebuf, "\\$");
+           cp++;
+       }
+       else
+       {
+           /*
+            * Ordinary data character, transfer to pattern
+            *
+            * Inside double quotes, or at all times if force_escape is true,
+            * quote regexp special characters with a backslash to avoid
+            * regexp errors.  Outside quotes, however, let them pass through
+            * as-is; this lets knowledgeable users build regexp expressions
+            * that are more powerful than shell-style patterns.
+            */
+           if ((inquotes || force_escape) &&
+               strchr("|*+?()[]{}.^$\\", ch))
+               appendPQExpBufferChar(&namebuf, '\\');
+           i = PQmblen(cp, encoding);
+           while (i-- && *cp)
+           {
+               appendPQExpBufferChar(&namebuf, *cp);
+               cp++;
+           }
+       }
+   }
+
+   /*
+    * Now decide what we need to emit.  Note there will be a leading "^(" in
+    * the patterns in any case.
+    */
+   if (namebuf.len > 2)
+   {
+       /* We have a name pattern, so constrain the namevar(s) */
+
+       appendPQExpBufferStr(&namebuf, ")$");
+       /* Optimize away a "*" pattern */
+       if (strcmp(namebuf.data, "^(.*)$") != 0)
+       {
+           WHEREAND();
+           if (altnamevar)
+           {
+               appendPQExpBuffer(buf, "(%s ~ ", namevar);
+               appendStringLiteralConn(buf, namebuf.data, conn);
+               appendPQExpBuffer(buf, "\n        OR %s ~ ", altnamevar);
+               appendStringLiteralConn(buf, namebuf.data, conn);
+               appendPQExpBufferStr(buf, ")\n");
+           }
+           else
+           {
+               appendPQExpBuffer(buf, "%s ~ ", namevar);
+               appendStringLiteralConn(buf, namebuf.data, conn);
+               appendPQExpBufferChar(buf, '\n');
+           }
+       }
+   }
+
+   if (schemabuf.len > 2)
+   {
+       /* We have a schema pattern, so constrain the schemavar */
+
+       appendPQExpBufferStr(&schemabuf, ")$");
+       /* Optimize away a "*" pattern */
+       if (strcmp(schemabuf.data, "^(.*)$") != 0 && schemavar)
+       {
+           WHEREAND();
+           appendPQExpBuffer(buf, "%s ~ ", schemavar);
+           appendStringLiteralConn(buf, schemabuf.data, conn);
+           appendPQExpBufferChar(buf, '\n');
+       }
+   }
+   else
+   {
+       /* No schema pattern given, so select only visible objects */
+       if (visibilityrule)
+       {
+           WHEREAND();
+           appendPQExpBuffer(buf, "%s\n", visibilityrule);
+       }
+   }
+
+   termPQExpBuffer(&schemabuf);
+   termPQExpBuffer(&namebuf);
+
+   return added_clause;
+#undef WHEREAND
+}
index 314d3b03f5eeb81c386d027f96840a7990c67a03..cad8951f97d9cea0304291ad1efb8c4180507dc9 100644 (file)
@@ -16,8 +16,9 @@ include $(top_builddir)/src/Makefile.global
 all: pg_config.h pg_config_ext.h pg_config_os.h
 
 
-# Subdirectories containing headers for server-side dev
-SUBDIRS = access bootstrap catalog commands common datatype executor foreign \
+# Subdirectories containing installable headers
+SUBDIRS = access bootstrap catalog commands common datatype \
+   executor fe_utils foreign \
    lib libpq mb nodes optimizer parser postmaster regex replication \
    rewrite storage tcop snowball snowball/libstemmer tsearch \
    tsearch/dicts utils port port/atomics port/win32 port/win32_msvc \
diff --git a/src/include/fe_utils/simple_list.h b/src/include/fe_utils/simple_list.h
new file mode 100644 (file)
index 0000000..87d32fb
--- /dev/null
@@ -0,0 +1,55 @@
+/*-------------------------------------------------------------------------
+ *
+ * Simple list facilities for frontend code
+ *
+ * Data structures for simple lists of OIDs and strings.  The support for
+ * these is very primitive compared to the backend's List facilities, but
+ * it's all we need in, eg, pg_dump.
+ *
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/fe_utils/simple_list.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SIMPLE_LIST_H
+#define SIMPLE_LIST_H
+
+typedef struct SimpleOidListCell
+{
+   struct SimpleOidListCell *next;
+   Oid         val;
+} SimpleOidListCell;
+
+typedef struct SimpleOidList
+{
+   SimpleOidListCell *head;
+   SimpleOidListCell *tail;
+} SimpleOidList;
+
+typedef struct SimpleStringListCell
+{
+   struct SimpleStringListCell *next;
+   bool        touched;        /* true, when this string was searched and
+                                * touched */
+   char        val[FLEXIBLE_ARRAY_MEMBER];     /* null-terminated string here */
+} SimpleStringListCell;
+
+typedef struct SimpleStringList
+{
+   SimpleStringListCell *head;
+   SimpleStringListCell *tail;
+} SimpleStringList;
+
+
+extern void simple_oid_list_append(SimpleOidList *list, Oid val);
+extern bool simple_oid_list_member(SimpleOidList *list, Oid val);
+
+extern void simple_string_list_append(SimpleStringList *list, const char *val);
+extern bool simple_string_list_member(SimpleStringList *list, const char *val);
+
+extern const char *simple_string_list_not_touched(SimpleStringList *list);
+
+#endif   /* SIMPLE_LIST_H */
diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h
new file mode 100644 (file)
index 0000000..5d3fcc2
--- /dev/null
@@ -0,0 +1,51 @@
+/*-------------------------------------------------------------------------
+ *
+ * String-processing utility routines for frontend code
+ *
+ * Assorted utility functions that are useful in constructing SQL queries
+ * and interpreting backend output.
+ *
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/fe_utils/string_utils.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef STRING_UTILS_H
+#define STRING_UTILS_H
+
+#include "libpq-fe.h"
+#include "pqexpbuffer.h"
+
+#define atooid(x)  ((Oid) strtoul((x), NULL, 10))
+
+/* Global variables controlling behavior of fmtId() and fmtQualifiedId() */
+extern int quote_all_identifiers;
+extern PQExpBuffer (*getLocalPQExpBuffer) (void);
+
+/* Functions */
+extern const char *fmtId(const char *identifier);
+extern const char *fmtQualifiedId(int remoteVersion,
+              const char *schema, const char *id);
+
+extern void appendStringLiteral(PQExpBuffer buf, const char *str,
+                   int encoding, bool std_strings);
+extern void appendStringLiteralConn(PQExpBuffer buf, const char *str,
+                       PGconn *conn);
+extern void appendStringLiteralDQ(PQExpBuffer buf, const char *str,
+                     const char *dqprefix);
+extern void appendByteaLiteral(PQExpBuffer buf,
+                  const unsigned char *str, size_t length,
+                  bool std_strings);
+
+extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
+
+extern bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf,
+                     const char *pattern,
+                     bool have_where, bool force_escape,
+                     const char *schemavar, const char *namevar,
+                     const char *altnamevar, const char *visibilityrule);
+
+#endif   /* STRING_UTILS_H */
index 8716642847ae2a0fe21595d554ffd5688956e2cd..f12addba02f48bd23495f067e50db9c4504e4dbf 100644 (file)
@@ -25,6 +25,7 @@ our (@ISA, @EXPORT_OK);
 my $solution;
 my $libpgport;
 my $libpgcommon;
+my $libpgfeutils;
 my $postgres;
 my $libpq;
 
@@ -62,7 +63,7 @@ my $frontend_extralibs = {
    'psql'       => ['ws2_32.lib'] };
 my $frontend_extraincludes = {
    'initdb' => ['src/timezone'],
-   'psql'   => [ 'src/bin/pg_dump', 'src/backend' ],
+   'psql'   => [ 'src/backend' ],
    'pgbench' => [ 'src/bin/psql' ] };
 my $frontend_extrasource = {
    'psql' => ['src/bin/psql/psqlscan.l', 'src/bin/psql/psqlscanslash.l'],
@@ -118,6 +119,9 @@ sub mkvcbuild
 
    our @pgcommonbkndfiles = @pgcommonallfiles;
 
+   our @pgfeutilsfiles = qw(
+     simple_list.c string_utils.c);
+
    $libpgport = $solution->AddProject('libpgport', 'lib', 'misc');
    $libpgport->AddDefine('FRONTEND');
    $libpgport->AddFiles('src/port', @pgportfiles);
@@ -126,6 +130,10 @@ sub mkvcbuild
    $libpgcommon->AddDefine('FRONTEND');
    $libpgcommon->AddFiles('src/common', @pgcommonfrontendfiles);
 
+   $libpgfeutils = $solution->AddProject('libpgfeutils', 'lib', 'misc');
+   $libpgfeutils->AddDefine('FRONTEND');
+   $libpgfeutils->AddFiles('src/fe_utils', @pgfeutilsfiles);
+
    $postgres = $solution->AddProject('postgres', 'exe', '', 'src/backend');
    $postgres->AddIncludeDir('src/backend');
    $postgres->AddDir('src/backend/port/win32');
@@ -613,11 +621,7 @@ sub mkvcbuild
        foreach my $f (@files)
        {
            $f =~ s/\.o$/\.c/;
-           if ($f eq 'dumputils.c')
-           {
-               $proj->AddFile('src/bin/pg_dump/dumputils.c');
-           }
-           elsif ($f =~ /print\.c$/)
+           if ($f =~ /print\.c$/)
            {    # Also catches mbprint.c
                $proj->AddFile('src/bin/psql/' . $f);
            }
@@ -627,9 +631,9 @@ sub mkvcbuild
            }
        }
        $proj->AddIncludeDir('src/interfaces/libpq');
-       $proj->AddIncludeDir('src/bin/pg_dump');
        $proj->AddIncludeDir('src/bin/psql');
-       $proj->AddReference($libpq, $libpgcommon, $libpgport);
+       $proj->AddReference($libpq, $libpgfeutils, $libpgcommon,
+                   $libpgport);
        $proj->AddDirResourceFile('src/bin/scripts');
        $proj->AddLibrary('ws2_32.lib');
    }
@@ -680,7 +684,7 @@ sub AddSimpleFrontend
 
    my $p = $solution->AddProject($n, 'exe', 'bin');
    $p->AddDir('src/bin/' . $n);
-   $p->AddReference($libpgcommon, $libpgport);
+   $p->AddReference($libpgfeutils, $libpgcommon, $libpgport);
    if ($uselibpq)
    {
        $p->AddIncludeDir('src/interfaces/libpq');