pg_dump support for function parameter names.
authorTom Lane
Wed, 7 Jan 2004 00:44:21 +0000 (00:44 +0000)
committerTom Lane
Wed, 7 Jan 2004 00:44:21 +0000 (00:44 +0000)
src/bin/pg_dump/dumputils.c
src/bin/pg_dump/dumputils.h
src/bin/pg_dump/pg_dump.c

index 1bb0181cf2e7abbe68e76d03dcffb3ce9c13d0de..16f0bd8877d55143a40dd49b665556c0da15be2b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.10 2003/11/29 19:52:05 pgsql Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.11 2004/01/07 00:44:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,6 @@
 
 #define supports_grant_options(version) ((version) >= 70400)
 
-static bool parseAclArray(const char *acls, char ***itemarray, int *nitems);
 static bool parseAclItem(const char *item, const char *type, const char *name,
             int remoteVersion,
             PQExpBuffer grantee, PQExpBuffer grantor,
@@ -166,6 +165,91 @@ parse_version(const char *versionString)
 }
 
 
+/*
+ * 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;
+}
+
+
 /*
  * Build GRANT/REVOKE command(s) for an object.
  *
@@ -202,7 +286,7 @@ buildACLCommands(const char *name, const char *type,
    if (strlen(acls) == 0)
        return true;            /* object has default permissions */
 
-   if (!parseAclArray(acls, &aclitems, &naclitems))
+   if (!parsePGArray(acls, &aclitems, &naclitems))
    {
        if (aclitems)
            free(aclitems);
@@ -341,90 +425,6 @@ buildACLCommands(const char *name, const char *type,
    return true;
 }
 
-/*
- * Deconstruct an ACL array (or actually any 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.
- */
-static bool
-parseAclArray(const char *acls, 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(acls);
-   if (inputlen < 2 || acls[0] != '{' || acls[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);
-
-   acls++;                     /* advance over initial '{' */
-   curitem = 0;
-   while (*acls != '}')
-   {
-       if (*acls == '\0')
-           return false;       /* premature end of string */
-       items[curitem] = strings;
-       while (*acls != '}' && *acls != ',')
-       {
-           if (*acls == '\0')
-               return false;   /* premature end of string */
-           if (*acls != '"')
-               *strings++ = *acls++;   /* copy unquoted data */
-           else
-           {
-               /* process quoted substring */
-               acls++;
-               while (*acls != '"')
-               {
-                   if (*acls == '\0')
-                       return false;   /* premature end of string */
-                   if (*acls == '\\')
-                   {
-                       acls++;
-                       if (*acls == '\0')
-                           return false;       /* premature end of string */
-                   }
-                   *strings++ = *acls++;       /* copy quoted data */
-               }
-               acls++;
-           }
-       }
-       *strings++ = '\0';
-       if (*acls == ',')
-           acls++;
-       curitem++;
-   }
-   if (acls[1] != '\0')
-       return false;           /* bogus syntax (embedded '}') */
-   *nitems = curitem;
-   return true;
-}
-
 /*
  * This will parse an aclitem string, having the general form
  *     username=privilegecodes/grantor
index 25a85f897c3746a45a8bb47a5cc18dedd5050b75..c4a71f1c43be39cf94495a1b3d4510ef064fec45 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.9 2003/11/29 22:40:46 pgsql Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.10 2004/01/07 00:44:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,7 @@ extern const char *fmtId(const char *identifier);
 extern void appendStringLiteral(PQExpBuffer buf, const char *str,
                    bool escapeAll);
 extern int parse_version(const char *versionString);
+extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
 extern bool buildACLCommands(const char *name, const char *type,
                 const char *acls, const char *owner,
                 int remoteVersion,
index 102cbc0f4acc9ba1afaaed47692fef42c743d29e..81473bfa0846f897cbebc7e104e6b264855961b6 100644 (file)
@@ -12,7 +12,7 @@
  * by PostgreSQL
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.361 2003/12/19 14:21:56 petere Exp $
+ *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.362 2004/01/07 00:44:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -135,7 +135,8 @@ static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 static void getDependencies(void);
 static void getDomainConstraints(TypeInfo *tinfo);
 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
-static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
+static char *format_function_signature(FuncInfo *finfo, char **argnames,
+                                      bool honor_quotes);
 static const char *convertRegProcReference(const char *proc);
 static const char *convertOperatorReference(const char *opr);
 static Oid findLastBuiltinOid_V71(const char *);
@@ -4650,9 +4651,12 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
  *
  * The argument type names are qualified if needed.  The function name
  * is never qualified.
+ *
+ * argnames may be NULL if no names are available.
  */
 static char *
-format_function_signature(FuncInfo *finfo, bool honor_quotes)
+format_function_signature(FuncInfo *finfo, char **argnames,
+                         bool honor_quotes)
 {
    PQExpBufferData fn;
    int         j;
@@ -4665,10 +4669,18 @@ format_function_signature(FuncInfo *finfo, bool honor_quotes)
    for (j = 0; j < finfo->nargs; j++)
    {
        char       *typname;
+       char       *argname;
 
        typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
-       appendPQExpBuffer(&fn, "%s%s",
+
+       argname = argnames ? argnames[j] : (char *) NULL;
+       if (argname && argname[0] == '\0')
+           argname = NULL;
+
+       appendPQExpBuffer(&fn, "%s%s%s%s",
                          (j > 0) ? ", " : "",
+                         argname ? fmtId(argname) : "",
+                         argname ? " " : "",
                          typname);
        free(typname);
    }
@@ -4695,11 +4707,13 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
    char       *proretset;
    char       *prosrc;
    char       *probin;
+   char       *proargnames;
    char       *provolatile;
    char       *proisstrict;
    char       *prosecdef;
    char       *lanname;
    char       *rettypename;
+   char      **argnamearray = NULL;
 
    /* Dump only funcs in dumpable namespaces */
    if (!finfo->pronamespace->dump || dataOnly)
@@ -4714,10 +4728,22 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
    selectSourceSchema(finfo->pronamespace->nspname);
 
    /* Fetch function-specific details */
-   if (g_fout->remoteVersion >= 70300)
+   if (g_fout->remoteVersion >= 70500)
    {
        appendPQExpBuffer(query,
                          "SELECT proretset, prosrc, probin, "
+                         "proargnames, "
+                         "provolatile, proisstrict, prosecdef, "
+                         "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
+                         "FROM pg_catalog.pg_proc "
+                         "WHERE oid = '%u'::pg_catalog.oid",
+                         finfo->dobj.catId.oid);
+   }
+   else if (g_fout->remoteVersion >= 70300)
+   {
+       appendPQExpBuffer(query,
+                         "SELECT proretset, prosrc, probin, "
+                         "null::text as proargnames, "
                          "provolatile, proisstrict, prosecdef, "
                          "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
                          "FROM pg_catalog.pg_proc "
@@ -4728,6 +4754,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
    {
        appendPQExpBuffer(query,
                          "SELECT proretset, prosrc, probin, "
+                         "null::text as proargnames, "
         "case when proiscachable then 'i' else 'v' end as provolatile, "
                          "proisstrict, "
                          "'f'::boolean as prosecdef, "
@@ -4740,6 +4767,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
    {
        appendPQExpBuffer(query,
                          "SELECT proretset, prosrc, probin, "
+                         "null::text as proargnames, "
         "case when proiscachable then 'i' else 'v' end as provolatile, "
                          "'f'::boolean as proisstrict, "
                          "'f'::boolean as prosecdef, "
@@ -4764,6 +4792,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
    proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
    prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
    probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
+   proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
    provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
    proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
    prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
@@ -4792,8 +4821,22 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
        }
    }
 
-   funcsig = format_function_signature(finfo, true);
-   funcsig_tag = format_function_signature(finfo, false);
+   if (proargnames && *proargnames)
+   {
+       int     nitems = 0;
+
+       if (!parsePGArray(proargnames, &argnamearray, &nitems) ||
+           nitems != finfo->nargs)
+       {
+           write_msg(NULL, "WARNING: could not parse proargnames array\n");
+           if (argnamearray)
+               free(argnamearray);
+           argnamearray = NULL;
+       }
+   }
+
+   funcsig = format_function_signature(finfo, argnamearray, true);
+   funcsig_tag = format_function_signature(finfo, NULL, false);
 
    /*
     * DROP must be fully qualified in case same name appears in
@@ -4864,6 +4907,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
    destroyPQExpBuffer(asPart);
    free(funcsig);
    free(funcsig_tag);
+   if (argnamearray)
+       free(argnamearray);
 }
 
 
@@ -4953,7 +4998,7 @@ dumpCast(Archive *fout, CastInfo *cast)
        appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
    else
        appendPQExpBuffer(defqry, "WITH FUNCTION %s",
-                         format_function_signature(funcInfo, true));
+                         format_function_signature(funcInfo, NULL, true));
 
    if (cast->castcontext == 'a')
        appendPQExpBuffer(defqry, " AS ASSIGNMENT");
@@ -5892,8 +5937,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
    free(aggsig);
    free(aggsig_tag);
 
-   aggsig = format_function_signature(&agginfo->aggfn, true);
-   aggsig_tag = format_function_signature(&agginfo->aggfn, false);
+   aggsig = format_function_signature(&agginfo->aggfn, NULL, true);
+   aggsig_tag = format_function_signature(&agginfo->aggfn, NULL, false);
 
    dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
            "FUNCTION",