diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 1bb0181cf2..16f0bd8877 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, @@ -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 diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h index 25a85f897c..c4a71f1c43 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 102cbc0f4a..81473bfa08 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",