]> granicus.if.org Git - postgresql/commitdiff
Create src/fe_utils/, and move stuff into there from pg_dump's dumputils.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 24 Mar 2016 19:55:44 +0000 (15:55 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
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 <ctype.h>
 
 #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 <ctype.h>
-
 #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 <sys/types.h>
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 <ctype.h>
 #include <fcntl.h>
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 <sys/stat.h>
 #include <ctype.h>
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 <ctype.h>
 
 #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 <ctype.h>
+
+#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');