summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2004-01-07 00:44:21 +0000
committerTom Lane2004-01-07 00:44:21 +0000
commit6400d69d8790298c9f6c0530c92356160ded70e4 (patch)
tree86e86991a1bc30a4500cd161dd447cbc0533baea
parenta77e32d7c5615e302fbc87803086132f1dab99a9 (diff)
pg_dump support for function parameter names.
-rw-r--r--src/bin/pg_dump/dumputils.c174
-rw-r--r--src/bin/pg_dump/dumputils.h3
-rw-r--r--src/bin/pg_dump/pg_dump.c65
3 files changed, 144 insertions, 98 deletions
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 1bb0181cf2e..16f0bd8877d 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -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,
@@ -167,6 +166,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.
*
* name: the object name, in the form to use in the commands (already quoted)
@@ -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);
@@ -342,90 +426,6 @@ buildACLCommands(const char *name, const char *type,
}
/*
- * 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
* or
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index 25a85f897c3..c4a71f1c43b 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -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,
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 102cbc0f4ac..81473bfa084 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -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",