]> granicus.if.org Git - postgresql/commitdiff
pg_dump support for function parameter names.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 7 Jan 2004 00:44:21 +0000 (00:44 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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",