Commit 6400d69d authored by Tom Lane's avatar Tom Lane

pg_dump support for function parameter names.

parent a77e32d7
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -21,7 +21,6 @@
#define supports_grant_options(version) ((version) >= 70400) #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, static bool parseAclItem(const char *item, const char *type, const char *name,
int remoteVersion, int remoteVersion,
PQExpBuffer grantee, PQExpBuffer grantor, PQExpBuffer grantee, PQExpBuffer grantor,
...@@ -166,6 +165,91 @@ parse_version(const char *versionString) ...@@ -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. * Build GRANT/REVOKE command(s) for an object.
* *
...@@ -202,7 +286,7 @@ buildACLCommands(const char *name, const char *type, ...@@ -202,7 +286,7 @@ buildACLCommands(const char *name, const char *type,
if (strlen(acls) == 0) if (strlen(acls) == 0)
return true; /* object has default permissions */ return true; /* object has default permissions */
if (!parseAclArray(acls, &aclitems, &naclitems)) if (!parsePGArray(acls, &aclitems, &naclitems))
{ {
if (aclitems) if (aclitems)
free(aclitems); free(aclitems);
...@@ -341,90 +425,6 @@ buildACLCommands(const char *name, const char *type, ...@@ -341,90 +425,6 @@ buildACLCommands(const char *name, const char *type,
return true; 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 * This will parse an aclitem string, having the general form
* username=privilegecodes/grantor * username=privilegecodes/grantor
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -22,6 +22,7 @@ extern const char *fmtId(const char *identifier);
extern void appendStringLiteral(PQExpBuffer buf, const char *str, extern void appendStringLiteral(PQExpBuffer buf, const char *str,
bool escapeAll); bool escapeAll);
extern int parse_version(const char *versionString); 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, extern bool buildACLCommands(const char *name, const char *type,
const char *acls, const char *owner, const char *acls, const char *owner,
int remoteVersion, int remoteVersion,
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * 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, ...@@ -135,7 +135,8 @@ static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
static void getDependencies(void); static void getDependencies(void);
static void getDomainConstraints(TypeInfo *tinfo); static void getDomainConstraints(TypeInfo *tinfo);
static void getTableData(TableInfo *tblinfo, int numTables, bool oids); 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 *convertRegProcReference(const char *proc);
static const char *convertOperatorReference(const char *opr); static const char *convertOperatorReference(const char *opr);
static Oid findLastBuiltinOid_V71(const char *); static Oid findLastBuiltinOid_V71(const char *);
...@@ -4650,9 +4651,12 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) ...@@ -4650,9 +4651,12 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
* *
* The argument type names are qualified if needed. The function name * The argument type names are qualified if needed. The function name
* is never qualified. * is never qualified.
*
* argnames may be NULL if no names are available.
*/ */
static char * static char *
format_function_signature(FuncInfo *finfo, bool honor_quotes) format_function_signature(FuncInfo *finfo, char **argnames,
bool honor_quotes)
{ {
PQExpBufferData fn; PQExpBufferData fn;
int j; int j;
...@@ -4665,10 +4669,18 @@ format_function_signature(FuncInfo *finfo, bool honor_quotes) ...@@ -4665,10 +4669,18 @@ format_function_signature(FuncInfo *finfo, bool honor_quotes)
for (j = 0; j < finfo->nargs; j++) for (j = 0; j < finfo->nargs; j++)
{ {
char *typname; char *typname;
char *argname;
typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque); 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) ? ", " : "", (j > 0) ? ", " : "",
argname ? fmtId(argname) : "",
argname ? " " : "",
typname); typname);
free(typname); free(typname);
} }
...@@ -4695,11 +4707,13 @@ dumpFunc(Archive *fout, FuncInfo *finfo) ...@@ -4695,11 +4707,13 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
char *proretset; char *proretset;
char *prosrc; char *prosrc;
char *probin; char *probin;
char *proargnames;
char *provolatile; char *provolatile;
char *proisstrict; char *proisstrict;
char *prosecdef; char *prosecdef;
char *lanname; char *lanname;
char *rettypename; char *rettypename;
char **argnamearray = NULL;
/* Dump only funcs in dumpable namespaces */ /* Dump only funcs in dumpable namespaces */
if (!finfo->pronamespace->dump || dataOnly) if (!finfo->pronamespace->dump || dataOnly)
...@@ -4714,10 +4728,22 @@ dumpFunc(Archive *fout, FuncInfo *finfo) ...@@ -4714,10 +4728,22 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
selectSourceSchema(finfo->pronamespace->nspname); selectSourceSchema(finfo->pronamespace->nspname);
/* Fetch function-specific details */ /* 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, appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, " "SELECT proretset, prosrc, probin, "
"null::text as proargnames, "
"provolatile, proisstrict, prosecdef, " "provolatile, proisstrict, prosecdef, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname " "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
"FROM pg_catalog.pg_proc " "FROM pg_catalog.pg_proc "
...@@ -4728,6 +4754,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) ...@@ -4728,6 +4754,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
{ {
appendPQExpBuffer(query, appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, " "SELECT proretset, prosrc, probin, "
"null::text as proargnames, "
"case when proiscachable then 'i' else 'v' end as provolatile, " "case when proiscachable then 'i' else 'v' end as provolatile, "
"proisstrict, " "proisstrict, "
"'f'::boolean as prosecdef, " "'f'::boolean as prosecdef, "
...@@ -4740,6 +4767,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) ...@@ -4740,6 +4767,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
{ {
appendPQExpBuffer(query, appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, " "SELECT proretset, prosrc, probin, "
"null::text as proargnames, "
"case when proiscachable then 'i' else 'v' end as provolatile, " "case when proiscachable then 'i' else 'v' end as provolatile, "
"'f'::boolean as proisstrict, " "'f'::boolean as proisstrict, "
"'f'::boolean as prosecdef, " "'f'::boolean as prosecdef, "
...@@ -4764,6 +4792,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) ...@@ -4764,6 +4792,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset")); proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc")); prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
probin = PQgetvalue(res, 0, PQfnumber(res, "probin")); probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile")); provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict")); proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef")); prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
...@@ -4792,8 +4821,22 @@ dumpFunc(Archive *fout, FuncInfo *finfo) ...@@ -4792,8 +4821,22 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
} }
} }
funcsig = format_function_signature(finfo, true); if (proargnames && *proargnames)
funcsig_tag = format_function_signature(finfo, false); {
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 * DROP must be fully qualified in case same name appears in
...@@ -4864,6 +4907,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) ...@@ -4864,6 +4907,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
destroyPQExpBuffer(asPart); destroyPQExpBuffer(asPart);
free(funcsig); free(funcsig);
free(funcsig_tag); free(funcsig_tag);
if (argnamearray)
free(argnamearray);
} }
...@@ -4953,7 +4998,7 @@ dumpCast(Archive *fout, CastInfo *cast) ...@@ -4953,7 +4998,7 @@ dumpCast(Archive *fout, CastInfo *cast)
appendPQExpBuffer(defqry, "WITHOUT FUNCTION"); appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
else else
appendPQExpBuffer(defqry, "WITH FUNCTION %s", appendPQExpBuffer(defqry, "WITH FUNCTION %s",
format_function_signature(funcInfo, true)); format_function_signature(funcInfo, NULL, true));
if (cast->castcontext == 'a') if (cast->castcontext == 'a')
appendPQExpBuffer(defqry, " AS ASSIGNMENT"); appendPQExpBuffer(defqry, " AS ASSIGNMENT");
...@@ -5892,8 +5937,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo) ...@@ -5892,8 +5937,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
free(aggsig); free(aggsig);
free(aggsig_tag); free(aggsig_tag);
aggsig = format_function_signature(&agginfo->aggfn, true); aggsig = format_function_signature(&agginfo->aggfn, NULL, true);
aggsig_tag = format_function_signature(&agginfo->aggfn, false); aggsig_tag = format_function_signature(&agginfo->aggfn, NULL, false);
dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId, dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
"FUNCTION", "FUNCTION",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment