mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
pg_dump support for function parameter names.
This commit is contained in:
@ -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 @@
|
|||||||
|
|
||||||
#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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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,
|
|||||||
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,
|
|||||||
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 @@
|
|||||||
* 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);
|
|||||||
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 @@
|
|||||||
* 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,
|
|||||||
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)
|
|||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
appendPQExpBuffer(query,
|
||||||
"SELECT proretset, prosrc, probin, "
|
"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, "
|
"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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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",
|
||||||
|
Reference in New Issue
Block a user