Update bdr_dump to 9.4.2 + --snapshot
authorCraig Ringer <craig@2ndquadrant.com>
Tue, 26 May 2015 06:12:43 +0000 (14:12 +0800)
committerCraig Ringer <craig@2ndquadrant.com>
Fri, 29 May 2015 13:04:46 +0000 (21:04 +0800)
Update copy of pg_dump with snapshot support for UDR to the
version from bdr-pg/REL9_4_STABLE . We can't use stock pg_dump
because we need support for dumping from a pre-established
snapshot, which is added in the BDR tree.

Makefile.in
pg_dump/compress_io.c
pg_dump/dumputils.c
pg_dump/kwlookup.c [new file with mode: 0644]
pg_dump/parallel.c
pg_dump/pg_dump.c
pg_dump/pg_dump.h
pg_dump/pg_dump_sort.c

index 48bf4f5f6b620f6ead3548b0a66624047d675e92..52153c7c16a35df3c08b86a58e941c89cf69b23c 100644 (file)
@@ -92,7 +92,7 @@ DUMPOBJS = pg_dump/pg_dump.o pg_dump/common.o pg_dump/pg_dump_sort.o \
    pg_dump/pg_backup_tar.o pg_dump/pg_backup_directory.o \
    pg_dump/pg_backup_utils.o pg_dump/parallel.o \
    pg_dump/compress_io.o pg_dump/dumputils.o \
-   pg_dump/keywords.o
+   pg_dump/keywords.o pg_dump/kwlookup.o
 
 include Makefile.global
 
index 2e2a447ae78189127a3f756224280a0d425a46f4..ffced11a02e1001d7abfae006b1dd6b1b4cced3b 100644 (file)
@@ -452,6 +452,16 @@ struct cfp
 static int hasSuffix(const char *filename, const char *suffix);
 #endif
 
+/* free() without changing errno; useful in several places below */
+static void
+free_keep_errno(void *p)
+{
+   int         save_errno = errno;
+
+   free(p);
+   errno = save_errno;
+}
+
 /*
  * Open a file for reading. 'path' is the file to open, and 'mode' should
  * be either "r" or "rb".
@@ -459,6 +469,8 @@ static int  hasSuffix(const char *filename, const char *suffix);
  * If the file at 'path' does not exist, we append the ".gz" suffix (if 'path'
  * doesn't already have it) and try again. So if you pass "foo" as 'path',
  * this will open either "foo" or "foo.gz".
+ *
+ * On failure, return NULL with an error code in errno.
  */
 cfp *
 cfopen_read(const char *path, const char *mode)
@@ -479,7 +491,7 @@ cfopen_read(const char *path, const char *mode)
 
            fname = psprintf("%s.gz", path);
            fp = cfopen(fname, mode, 1);
-           free(fname);
+           free_keep_errno(fname);
        }
 #endif
    }
@@ -492,8 +504,10 @@ cfopen_read(const char *path, const char *mode)
  * ("w", "wb", "a", or "ab").
  *
  * If 'compression' is non-zero, a gzip compressed stream is opened, and
- * and 'compression' indicates the compression level used. The ".gz" suffix
+ * 'compression' indicates the compression level used. The ".gz" suffix
  * is automatically added to 'path' in that case.
+ *
+ * On failure, return NULL with an error code in errno.
  */
 cfp *
 cfopen_write(const char *path, const char *mode, int compression)
@@ -508,8 +522,8 @@ cfopen_write(const char *path, const char *mode, int compression)
        char       *fname;
 
        fname = psprintf("%s.gz", path);
-       fp = cfopen(fname, mode, 1);
-       free(fname);
+       fp = cfopen(fname, mode, compression);
+       free_keep_errno(fname);
 #else
        exit_horribly(modulename, "not built with zlib support\n");
        fp = NULL;              /* keep compiler quiet */
@@ -520,7 +534,9 @@ cfopen_write(const char *path, const char *mode, int compression)
 
 /*
  * Opens file 'path' in 'mode'. If 'compression' is non-zero, the file
- * is opened with libz gzopen(), otherwise with plain fopen()
+ * is opened with libz gzopen(), otherwise with plain fopen().
+ *
+ * On failure, return NULL with an error code in errno.
  */
 cfp *
 cfopen(const char *path, const char *mode, int compression)
@@ -530,11 +546,15 @@ cfopen(const char *path, const char *mode, int compression)
    if (compression != 0)
    {
 #ifdef HAVE_LIBZ
-       fp->compressedfp = gzopen(path, mode);
+       char        mode_compression[32];
+
+       snprintf(mode_compression, sizeof(mode_compression), "%s%d",
+                mode, compression);
+       fp->compressedfp = gzopen(path, mode_compression);
        fp->uncompressedfp = NULL;
        if (fp->compressedfp == NULL)
        {
-           free(fp);
+           free_keep_errno(fp);
            fp = NULL;
        }
 #else
@@ -549,7 +569,7 @@ cfopen(const char *path, const char *mode, int compression)
        fp->uncompressedfp = fopen(path, mode);
        if (fp->uncompressedfp == NULL)
        {
-           free(fp);
+           free_keep_errno(fp);
            fp = NULL;
        }
    }
@@ -658,7 +678,7 @@ cfclose(cfp *fp)
        result = fclose(fp->uncompressedfp);
        fp->uncompressedfp = NULL;
    }
-   free(fp);
+   free_keep_errno(fp);
 
    return result;
 }
index 4a5c2ab60c9014049e0496fa1e5edf0dc75a333e..bc5f36611f253a39316323e7c1ba45cb246f55e1 100644 (file)
 #include "parser/keywords.h"
 
 
+/* Globals from keywords.c */
+extern const ScanKeyword FEScanKeywords[];
+extern const int NumFEScanKeywords;
+
 #define supports_grant_options(version) ((version) >= 70400)
 
 static bool parseAclItem(const char *item, const char *type,
@@ -75,20 +79,71 @@ 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;
+           }
+       }
+   }
 
-   appendPQExpBufferChar(id_return, '\"');
-   for (cp = rawid; *cp; cp++)
+   if (!need_quotes)
    {
        /*
-        * 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
+        * 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.
         */
-       if (*cp == '\"')
-           appendPQExpBufferChar(id_return, '\"');
-       appendPQExpBufferChar(id_return, *cp);
+       const ScanKeyword *keyword = ScanKeywordLookup(rawid,
+                                                      FEScanKeywords,
+                                                      NumFEScanKeywords);
+
+       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, '\"');
    }
-   appendPQExpBufferChar(id_return, '\"');
 
    return id_return->data;
 }
@@ -445,6 +500,7 @@ buildACLCommands(const char *name, const char *subname,
                 const char *prefix, int remoteVersion,
                 PQExpBuffer sql)
 {
+   bool        ok = true;
    char      **aclitems;
    int         naclitems;
    int         i;
@@ -515,8 +571,8 @@ buildACLCommands(const char *name, const char *subname,
        if (!parseAclItem(aclitems[i], type, name, subname, remoteVersion,
                          grantee, grantor, privs, privswgo))
        {
-           free(aclitems);
-           return false;
+           ok = false;
+           break;
        }
 
        if (grantor->len == 0 && owner)
@@ -623,7 +679,7 @@ buildACLCommands(const char *name, const char *subname,
 
    free(aclitems);
 
-   return true;
+   return ok;
 }
 
 /*
diff --git a/pg_dump/kwlookup.c b/pg_dump/kwlookup.c
new file mode 100644 (file)
index 0000000..af05aa7
--- /dev/null
@@ -0,0 +1,89 @@
+/*-------------------------------------------------------------------------
+ *
+ * kwlookup.c
+ *   lexical token lookup for key words in PostgreSQL
+ *
+ * NB - this file is also used by ECPG and several frontend programs in
+ * src/bin/ including pg_dump and psql
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   src/backend/parser/kwlookup.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/* use c.h so this can be built as either frontend or backend */
+#include "c.h"
+
+#include <ctype.h>
+
+#include "parser/keywords.h"
+
+/*
+ * ScanKeywordLookup - see if a given word is a keyword
+ *
+ * Returns a pointer to the ScanKeyword table entry, or NULL if no match.
+ *
+ * The match is done case-insensitively.  Note that we deliberately use a
+ * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z',
+ * even if we are in a locale where tolower() would produce more or different
+ * translations.  This is to conform to the SQL99 spec, which says that
+ * keywords are to be matched in this way even though non-keyword identifiers
+ * receive a different case-normalization mapping.
+ */
+const ScanKeyword *
+ScanKeywordLookup(const char *text,
+                 const ScanKeyword *keywords,
+                 int num_keywords)
+{
+   int         len,
+               i;
+   char        word[NAMEDATALEN];
+   const ScanKeyword *low;
+   const ScanKeyword *high;
+
+   len = strlen(text);
+   /* We assume all keywords are shorter than NAMEDATALEN. */
+   if (len >= NAMEDATALEN)
+       return NULL;
+
+   /*
+    * Apply an ASCII-only downcasing.  We must not use tolower() since it may
+    * produce the wrong translation in some locales (eg, Turkish).
+    */
+   for (i = 0; i < len; i++)
+   {
+       char        ch = text[i];
+
+       if (ch >= 'A' && ch <= 'Z')
+           ch += 'a' - 'A';
+       word[i] = ch;
+   }
+   word[len] = '\0';
+
+   /*
+    * Now do a binary search using plain strcmp() comparison.
+    */
+   low = keywords;
+   high = keywords + (num_keywords - 1);
+   while (low <= high)
+   {
+       const ScanKeyword *middle;
+       int         difference;
+
+       middle = low + (high - low) / 2;
+       difference = strcmp(middle->name, word);
+       if (difference == 0)
+           return middle;
+       else if (difference < 0)
+           low = middle + 1;
+       else
+           high = middle - 1;
+   }
+
+   return NULL;
+}
index e50dd8b43f8a8aa42fa4a11561d7c4db307206c0..64f5ac15033db1187ae1133310830601d51d5b3e 100644 (file)
@@ -816,7 +816,7 @@ lockTableNoWait(ArchiveHandle *AH, TocEntry *te)
                      "       pg_class.relname "
                      "  FROM pg_class "
                    "  JOIN pg_namespace on pg_namespace.oid = relnamespace "
-                     " WHERE pg_class.oid = %d", te->catalogId.oid);
+                     " WHERE pg_class.oid = %u", te->catalogId.oid);
 
    res = PQexec(AH->connection, query->data);
 
@@ -1303,7 +1303,7 @@ readMessageFromPipe(int fd)
        {
            /* could be any number */
            bufsize += 16;
-           msg = (char *) realloc(msg, bufsize);
+           msg = (char *) pg_realloc(msg, bufsize);
        }
    }
 
@@ -1311,7 +1311,7 @@ readMessageFromPipe(int fd)
     * Worker has closed the connection, make sure to clean up before return
     * since we are not returning msg (but did allocate it).
     */
-   free(msg);
+   pg_free(msg);
 
    return NULL;
 }
index 9c5a7e082018c57e12f095703f9c0307b73edb0f..8d07387c2046da787666a088f7dcd6619a5593a0 100644 (file)
@@ -1026,7 +1026,15 @@ setup_connection(Archive *AH, const char *dumpencoding,
    ExecuteSqlStatement(AH, "BEGIN");
    if (AH->remoteVersion >= 90100)
    {
-       if (serializable_deferrable)
+       /*
+        * To support the combination of serializable_deferrable with the jobs
+        * option we use REPEATABLE READ for the worker connections that are
+        * passed a snapshot.  As long as the snapshot is acquired in a
+        * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
+        * REPEATABLE READ transaction provides the appropriate integrity
+        * guarantees.  This is a kluge, but safe for back-patching.
+        */
+       if (serializable_deferrable && AH->sync_snapshot_id == NULL)
            ExecuteSqlStatement(AH,
                                "SET TRANSACTION ISOLATION LEVEL "
                                "SERIALIZABLE, READ ONLY, DEFERRABLE");
@@ -1347,6 +1355,24 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo)
        dinfo->dobj.dump = include_everything;
 }
 
+/*
+ * selectDumpableCast: policy-setting subroutine
+ *     Mark a cast as to be dumped or not
+ *
+ * Casts do not belong to any particular namespace (since they haven't got
+ * names), nor do they have identifiable owners.  To distinguish user-defined
+ * casts from built-in ones, we must resort to checking whether the cast's
+ * OID is in the range reserved for initdb.
+ */
+static void
+selectDumpableCast(CastInfo *cast)
+{
+   if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
+       cast->dobj.dump = false;
+   else
+       cast->dobj.dump = include_everything;
+}
+
 /*
  * selectDumpableExtension: policy-setting subroutine
  *     Mark an extension as to be dumped or not
@@ -2478,25 +2504,29 @@ dumpDatabase(Archive *fout)
                    dbCatId, 0, dbDumpId);
    }
 
-   PQclear(res);
-
    /* Dump shared security label. */
    if (!no_security_labels && fout->remoteVersion >= 90200)
    {
-       PQExpBuffer seclabelQry = createPQExpBuffer();
+       PGresult   *shres;
+       PQExpBuffer seclabelQry;
+
+       seclabelQry = createPQExpBuffer();
 
        buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
-       res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
+       shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
        resetPQExpBuffer(seclabelQry);
-       emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
+       emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
        if (strlen(seclabelQry->data))
            ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
                         dba, false, "SECURITY LABEL", SECTION_NONE,
                         seclabelQry->data, "", NULL,
                         &dbDumpId, 1, NULL, NULL);
        destroyPQExpBuffer(seclabelQry);
+       PQclear(shres);
    }
 
+   PQclear(res);
+
    destroyPQExpBuffer(dbQry);
    destroyPQExpBuffer(delQry);
    destroyPQExpBuffer(creaQry);
@@ -3934,7 +3964,6 @@ getAggregates(Archive *fout, int *numAggs)
    int         i_proargtypes;
    int         i_rolname;
    int         i_aggacl;
-   int         i_proiargs;
 
    /* Make sure we are in proper schema */
    selectSourceSchema(fout, "pg_catalog");
@@ -3944,12 +3973,11 @@ getAggregates(Archive *fout, int *numAggs)
     * rationale behind the filtering logic.
     */
 
-   if (fout->remoteVersion >= 80400)
+   if (fout->remoteVersion >= 80200)
    {
        appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
                          "pronamespace AS aggnamespace, "
                          "pronargs, proargtypes, "
-           "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
                          "(%s proowner) AS rolname, "
                          "proacl AS aggacl "
                          "FROM pg_proc p "
@@ -3967,28 +3995,12 @@ getAggregates(Archive *fout, int *numAggs)
                                 "deptype = 'e')");
        appendPQExpBufferChar(query, ')');
    }
-   else if (fout->remoteVersion >= 80200)
-   {
-       appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
-                         "pronamespace AS aggnamespace, "
-                         "pronargs, proargtypes, "
-                         "NULL::text AS proiargs,"
-                         "(%s proowner) AS rolname, "
-                         "proacl AS aggacl "
-                         "FROM pg_proc p "
-                         "WHERE proisagg AND ("
-                         "pronamespace != "
-                         "(SELECT oid FROM pg_namespace "
-                         "WHERE nspname = 'pg_catalog'))",
-                         username_subquery);
-   }
    else if (fout->remoteVersion >= 70300)
    {
        appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
                          "pronamespace AS aggnamespace, "
                          "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
                          "proargtypes, "
-                         "NULL::text AS proiargs, "
                          "(%s proowner) AS rolname, "
                          "proacl AS aggacl "
                          "FROM pg_proc "
@@ -4003,7 +4015,6 @@ getAggregates(Archive *fout, int *numAggs)
                          "0::oid AS aggnamespace, "
                  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
                          "aggbasetype AS proargtypes, "
-                         "NULL::text AS proiargs, "
                          "(%s aggowner) AS rolname, "
                          "'{=X}' AS aggacl "
                          "FROM pg_aggregate "
@@ -4019,7 +4030,6 @@ getAggregates(Archive *fout, int *numAggs)
                          "0::oid AS aggnamespace, "
                  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
                          "aggbasetype AS proargtypes, "
-                         "NULL::text AS proiargs, "
                          "(%s aggowner) AS rolname, "
                          "'{=X}' AS aggacl "
                          "FROM pg_aggregate "
@@ -4043,7 +4053,6 @@ getAggregates(Archive *fout, int *numAggs)
    i_proargtypes = PQfnumber(res, "proargtypes");
    i_rolname = PQfnumber(res, "rolname");
    i_aggacl = PQfnumber(res, "aggacl");
-   i_proiargs = PQfnumber(res, "proiargs");
 
    for (i = 0; i < ntups; i++)
    {
@@ -4063,7 +4072,6 @@ getAggregates(Archive *fout, int *numAggs)
        agginfo[i].aggfn.lang = InvalidOid;     /* not currently interesting */
        agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
        agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
-       agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
        agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
        if (agginfo[i].aggfn.nargs == 0)
            agginfo[i].aggfn.argtypes = NULL;
@@ -4115,7 +4123,6 @@ getFuncs(Archive *fout, int *numFuncs)
    int         i_proargtypes;
    int         i_prorettype;
    int         i_proacl;
-   int         i_proiargs;
 
    /* Make sure we are in proper schema */
    selectSourceSchema(fout, "pg_catalog");
@@ -4136,13 +4143,12 @@ getFuncs(Archive *fout, int *numFuncs)
     * doesn't have; otherwise we might not get creation ordering correct.
     */
 
-   if (fout->remoteVersion >= 80400)
+   if (fout->remoteVersion >= 70300)
    {
        appendPQExpBuffer(query,
                          "SELECT tableoid, oid, proname, prolang, "
                          "pronargs, proargtypes, prorettype, proacl, "
                          "pronamespace, "
-           "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
                          "(%s proowner) AS rolname "
                          "FROM pg_proc p "
                          "WHERE NOT proisagg AND ("
@@ -4164,21 +4170,6 @@ getFuncs(Archive *fout, int *numFuncs)
                                 "deptype = 'e')");
        appendPQExpBufferChar(query, ')');
    }
-   else if (fout->remoteVersion >= 70300)
-   {
-       appendPQExpBuffer(query,
-                         "SELECT tableoid, oid, proname, prolang, "
-                         "pronargs, proargtypes, prorettype, proacl, "
-                         "pronamespace, "
-                         "NULL::text AS proiargs,"
-                         "(%s proowner) AS rolname "
-                         "FROM pg_proc p "
-                         "WHERE NOT proisagg AND ("
-                         "pronamespace != "
-                         "(SELECT oid FROM pg_namespace "
-                         "WHERE nspname = 'pg_catalog'))",
-                         username_subquery);
-   }
    else if (fout->remoteVersion >= 70100)
    {
        appendPQExpBuffer(query,
@@ -4186,7 +4177,6 @@ getFuncs(Archive *fout, int *numFuncs)
                          "pronargs, proargtypes, prorettype, "
                          "'{=X}' AS proacl, "
                          "0::oid AS pronamespace, "
-                         "NULL::text AS proiargs,"
                          "(%s proowner) AS rolname "
                          "FROM pg_proc "
                          "WHERE pg_proc.oid > '%u'::oid",
@@ -4203,7 +4193,6 @@ getFuncs(Archive *fout, int *numFuncs)
                          "pronargs, proargtypes, prorettype, "
                          "'{=X}' AS proacl, "
                          "0::oid AS pronamespace, "
-                         "NULL::text AS proiargs,"
                          "(%s proowner) AS rolname "
                          "FROM pg_proc "
                          "where pg_proc.oid > '%u'::oid",
@@ -4229,7 +4218,6 @@ getFuncs(Archive *fout, int *numFuncs)
    i_proargtypes = PQfnumber(res, "proargtypes");
    i_prorettype = PQfnumber(res, "prorettype");
    i_proacl = PQfnumber(res, "proacl");
-   i_proiargs = PQfnumber(res, "proiargs");
 
    for (i = 0; i < ntups; i++)
    {
@@ -4245,7 +4233,6 @@ getFuncs(Archive *fout, int *numFuncs)
        finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
        finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
        finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
-       finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
        finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
        finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
        if (finfo[i].nargs == 0)
@@ -6259,12 +6246,13 @@ getCasts(Archive *fout, int *numCasts)
                              sTypeInfo->dobj.name, tTypeInfo->dobj.name);
        castinfo[i].dobj.name = namebuf.data;
 
-       if (OidIsValid(castinfo[i].castfunc))
+       if (fout->remoteVersion < 70300 &&
+           OidIsValid(castinfo[i].castfunc))
        {
            /*
             * We need to make a dependency to ensure the function will be
             * dumped first.  (In 7.3 and later the regular dependency
-            * mechanism will handle this for us.)
+            * mechanism handles this for us.)
             */
            FuncInfo   *funcInfo;
 
@@ -6273,6 +6261,9 @@ getCasts(Archive *fout, int *numCasts)
                addObjectDependency(&castinfo[i].dobj,
                                    funcInfo->dobj.dumpId);
        }
+
+       /* Decide whether we want to dump it */
+       selectDumpableCast(&(castinfo[i]));
    }
 
    PQclear(res);
@@ -8991,7 +8982,6 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
    int         i_attalign;
    int         i_attisdropped;
    int         i_attcollation;
-   int         i_typrelid;
    int         i;
    int         actual_atts;
 
@@ -9012,8 +9002,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
            "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
                          "a.attlen, a.attalign, a.attisdropped, "
                          "CASE WHEN a.attcollation <> at.typcollation "
-                         "THEN a.attcollation ELSE 0 END AS attcollation, "
-                         "ct.typrelid "
+                         "THEN a.attcollation ELSE 0 END AS attcollation "
                          "FROM pg_catalog.pg_type ct "
                "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
                    "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
@@ -9031,8 +9020,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
        appendPQExpBuffer(query, "SELECT a.attname, "
            "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
                          "a.attlen, a.attalign, a.attisdropped, "
-                         "0 AS attcollation, "
-                         "ct.typrelid "
+                         "0 AS attcollation "
                     "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
                          "WHERE ct.oid = '%u'::pg_catalog.oid "
                          "AND a.attrelid = ct.typrelid "
@@ -9050,15 +9038,12 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
    i_attalign = PQfnumber(res, "attalign");
    i_attisdropped = PQfnumber(res, "attisdropped");
    i_attcollation = PQfnumber(res, "attcollation");
-   i_typrelid = PQfnumber(res, "typrelid");
 
    if (binary_upgrade)
    {
-       Oid         typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
-
        binary_upgrade_set_type_oids_by_type_oid(fout, q,
                                                 tyinfo->dobj.catId.oid);
-       binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
+       binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
    }
 
    qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
@@ -10161,55 +10146,9 @@ dumpCast(Archive *fout, CastInfo *cast)
    }
 
    /*
-    * As per discussion we dump casts if one or more of the underlying
-    * objects (the conversion function and the two data types) are not
-    * builtin AND if all of the non-builtin objects are included in the dump.
-    * Builtin meaning, the namespace name does not start with "pg_".
-    *
-    * However, for a cast that belongs to an extension, we must not use this
-    * heuristic, but just dump the cast iff we're told to (via dobj.dump).
+    * Make sure we are in proper schema (needed for getFormattedTypeName).
+    * Casts don't have a schema of their own, so use pg_catalog.
     */
-   if (!cast->dobj.ext_member)
-   {
-       TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
-       TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
-
-       if (sourceInfo == NULL || targetInfo == NULL)
-           return;
-
-       /*
-        * Skip this cast if all objects are from pg_
-        */
-       if ((funcInfo == NULL ||
-            strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
-           strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
-           strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
-           return;
-
-       /*
-        * Skip cast if function isn't from pg_ and is not to be dumped.
-        */
-       if (funcInfo &&
-           strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
-           !funcInfo->dobj.dump)
-           return;
-
-       /*
-        * Same for the source type
-        */
-       if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
-           !sourceInfo->dobj.dump)
-           return;
-
-       /*
-        * and the target type.
-        */
-       if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
-           !targetInfo->dobj.dump)
-           return;
-   }
-
-   /* Make sure we are in proper schema (needed for getFormattedTypeName) */
    selectSourceSchema(fout, "pg_catalog");
 
    defqry = createPQExpBuffer();
@@ -14276,7 +14215,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
               *maxv = NULL,
               *minv = NULL,
               *cache,
-              *amname = NULL;
+              *amname = "local";
    char        bufm[100],
                bufx[100];
    bool        cycled;
@@ -14421,10 +14360,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
                      "    CACHE %s%s",
                      cache, (cycled ? "\n    CYCLE" : ""));
 
-   /* only dump sequence AM if pg_seqam exists */
-   if (amname)
-       appendPQExpBuffer(query, "\n    USING %s", fmtId(amname));
-
+   appendPQExpBuffer(query, "\n    USING %s", fmtId(amname));
    appendPQExpBufferStr(query, ";\n");
 
    appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
@@ -14816,7 +14752,7 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
        }
        appendPQExpBufferStr(query, ";\n");
    }
-   appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
+   appendPQExpBuffer(labelq, "EVENT TRIGGER %s",
                      fmtId(evtinfo->dobj.name));
 
    ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
@@ -14825,7 +14761,7 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
                 query->data, "", NULL, NULL, 0, NULL, NULL);
 
    dumpComment(fout, labelq->data,
-               NULL, NULL,
+               NULL, evtinfo->evtowner,
                evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
 
    destroyPQExpBuffer(query);
@@ -14967,6 +14903,33 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 
 /*
  * getExtensionMembership --- obtain extension membership data
+ *
+ * There are three main parts to this process:
+ *
+ * 1. Identify objects which are members of extensions
+ *
+ *    Generally speaking, this is to mark them as *not* being dumped, as most
+ *    extension objects are created by the single CREATE EXTENSION command.
+ *    The one exception is binary upgrades with pg_upgrade will still dump the
+ *    non-table objects.
+ *
+ * 2. Identify and create dump records for extension configuration tables.
+ *
+ *    Extensions can mark tables as "configuration", which means that the user
+ *    is able and expected to modify those tables after the extension has been
+ *    loaded.  For these tables, we dump out only the data- the structure is
+ *    expected to be handled at CREATE EXTENSION time, including any indexes or
+ *    foriegn keys, which brings us to-
+ *
+ * 3. Record FK dependencies between configuration tables.
+ *
+ *    Due to the FKs being created at CREATE EXTENSION time and therefore before
+ *    the data is loaded, we have to work out what the best order for reloading
+ *    the data is, to avoid FK violations when the tables are restored.  This is
+ *    not perfect- we can't handle circular dependencies and if any exist they
+ *    will cause an invalid dump to be produced (though at least all of the data
+ *    is included for a user to manually restore).  This is currently documented
+ *    but perhaps we can provide a better solution in the future.
  */
 void
 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
@@ -14979,7 +14942,9 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
    int         i_classid,
                i_objid,
                i_refclassid,
-               i_refobjid;
+               i_refobjid,
+               i_conrelid,
+               i_confrelid;
    DumpableObject *dobj,
               *refdobj;
 
@@ -15160,6 +15125,53 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
            free(extconditionarray);
    }
 
+   /*
+    * Now that all the TableInfoData objects have been created for all
+    * the extensions, check their FK dependencies and register them to
+    * try and dump the data out in an order which they can be restored
+    * in.
+    *
+    * Note that this is not a problem for user tables as their FKs are
+    * recreated after the data has been loaded.
+    */
+   printfPQExpBuffer(query,
+           "SELECT conrelid, confrelid "
+           "FROM pg_constraint "
+               "JOIN pg_depend ON (objid = confrelid) "
+           "WHERE contype = 'f' "
+           "AND refclassid = 'pg_extension'::regclass "
+           "AND classid = 'pg_class'::regclass;");
+
+   res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+   ntups = PQntuples(res);
+
+   i_conrelid = PQfnumber(res, "conrelid");
+   i_confrelid = PQfnumber(res, "confrelid");
+
+   /* Now get the dependencies and register them */
+   for (i = 0; i < ntups; i++)
+   {
+       Oid         conrelid, confrelid;
+       TableInfo  *reftable, *contable;
+
+       conrelid = atooid(PQgetvalue(res, i, i_conrelid));
+       confrelid = atooid(PQgetvalue(res, i, i_confrelid));
+       contable = findTableByOid(conrelid);
+       reftable = findTableByOid(confrelid);
+
+       if (reftable == NULL ||
+           reftable->dataObj == NULL ||
+           contable == NULL ||
+           contable->dataObj == NULL)
+           continue;
+
+       /*
+        * Make referencing TABLE_DATA object depend on the
+        * referenced table's TABLE_DATA object.
+        */
+       addObjectDependency(&contable->dataObj->dobj,
+                           reftable->dataObj->dobj.dumpId);
+   }
    destroyPQExpBuffer(query);
 }
 
index d18418758070286a4abf3b326f5849e2d2be01c5..da603744847fd55144d897bbf37e3a467c120d22 100644 (file)
@@ -184,7 +184,6 @@ typedef struct _funcInfo
    Oid        *argtypes;
    Oid         prorettype;
    char       *proacl;
-   char       *proiargs;
 } FuncInfo;
 
 /* AggInfo is a superset of FuncInfo */
index f0caa6b6599e1ec469a8de007e9f526865824e6e..6d970dd899993979db089a814ac514588a123dd8 100644 (file)
@@ -287,13 +287,30 @@ DOTypeNameCompare(const void *p1, const void *p2)
    {
        FuncInfo   *fobj1 = *(FuncInfo *const *) p1;
        FuncInfo   *fobj2 = *(FuncInfo *const *) p2;
+       int         i;
 
        cmpval = fobj1->nargs - fobj2->nargs;
        if (cmpval != 0)
            return cmpval;
-       cmpval = strcmp(fobj1->proiargs, fobj2->proiargs);
-       if (cmpval != 0)
-           return cmpval;
+       for (i = 0; i < fobj1->nargs; i++)
+       {
+           TypeInfo   *argtype1 = findTypeByOid(fobj1->argtypes[i]);
+           TypeInfo   *argtype2 = findTypeByOid(fobj2->argtypes[i]);
+
+           if (argtype1 && argtype2)
+           {
+               if (argtype1->dobj.namespace && argtype2->dobj.namespace)
+               {
+                   cmpval = strcmp(argtype1->dobj.namespace->dobj.name,
+                                   argtype2->dobj.namespace->dobj.name);
+                   if (cmpval != 0)
+                       return cmpval;
+               }
+               cmpval = strcmp(argtype1->dobj.name, argtype2->dobj.name);
+               if (cmpval != 0)
+                   return cmpval;
+           }
+       }
    }
    else if (obj1->objType == DO_OPERATOR)
    {