Commit 181f55e5 authored by Tom Lane's avatar Tom Lane

Fix up pg_dump to emit shell-type definitions at the proper time, to

make use of the recently added ability to create a shell type explicitly.

I also put in place some infrastructure to allow dump/no dump decisions
to be made separately for each database object, rather than the former
hardwired 'dump if in a dumpable schema' policy.  This was needed anyway
for shell types so now seemed a convenient time to do it.  The flexibility
isn't exposed to the user yet, but is ready for future extensions.
parent 305fcb7a
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.87 2005/10/15 02:49:38 momjian Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.88 2006/03/02 01:18:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -201,7 +201,7 @@ flagInhTables(TableInfo *tblinfo, int numTables, ...@@ -201,7 +201,7 @@ flagInhTables(TableInfo *tblinfo, int numTables,
continue; continue;
/* Don't bother computing anything for non-target tables, either */ /* Don't bother computing anything for non-target tables, either */
if (!tblinfo[i].dump) if (!tblinfo[i].dobj.dump)
continue; continue;
/* Find all the immediate parent tables */ /* Find all the immediate parent tables */
...@@ -242,7 +242,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -242,7 +242,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
continue; continue;
/* Don't bother computing anything for non-target tables, either */ /* Don't bother computing anything for non-target tables, either */
if (!tbinfo->dump) if (!tbinfo->dobj.dump)
continue; continue;
numParents = tbinfo->numParents; numParents = tbinfo->numParents;
...@@ -388,7 +388,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables, ...@@ -388,7 +388,7 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
* Given a newly-created dumpable object, assign a dump ID, * Given a newly-created dumpable object, assign a dump ID,
* and enter the object into the lookup table. * and enter the object into the lookup table.
* *
* The caller is expected to have filled in objType and catalogId, * The caller is expected to have filled in objType and catId,
* but not any of the other standard fields of a DumpableObject. * but not any of the other standard fields of a DumpableObject.
*/ */
void void
...@@ -397,6 +397,7 @@ AssignDumpId(DumpableObject *dobj) ...@@ -397,6 +397,7 @@ AssignDumpId(DumpableObject *dobj)
dobj->dumpId = ++lastDumpId; dobj->dumpId = ++lastDumpId;
dobj->name = NULL; /* must be set later */ dobj->name = NULL; /* must be set later */
dobj->namespace = NULL; /* may be set later */ dobj->namespace = NULL; /* may be set later */
dobj->dump = true; /* default assumption */
dobj->dependencies = NULL; dobj->dependencies = NULL;
dobj->nDeps = 0; dobj->nDeps = 0;
dobj->allocDeps = 0; dobj->allocDeps = 0;
......
...@@ -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.430 2006/02/21 18:01:32 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.431 2006/03/02 01:18:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -130,6 +130,7 @@ static void dumpType(Archive *fout, TypeInfo *tinfo); ...@@ -130,6 +130,7 @@ static void dumpType(Archive *fout, TypeInfo *tinfo);
static void dumpBaseType(Archive *fout, TypeInfo *tinfo); static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
static void dumpDomain(Archive *fout, TypeInfo *tinfo); static void dumpDomain(Archive *fout, TypeInfo *tinfo);
static void dumpCompositeType(Archive *fout, TypeInfo *tinfo); static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
static void dumpProcLang(Archive *fout, ProcLangInfo *plang); static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
static void dumpFunc(Archive *fout, FuncInfo *finfo); static void dumpFunc(Archive *fout, FuncInfo *finfo);
static void dumpCast(Archive *fout, CastInfo *cast); static void dumpCast(Archive *fout, CastInfo *cast);
...@@ -734,19 +735,19 @@ selectDumpableNamespace(NamespaceInfo *nsinfo) ...@@ -734,19 +735,19 @@ selectDumpableNamespace(NamespaceInfo *nsinfo)
* namespace. Otherwise, dump all non-system namespaces. * namespace. Otherwise, dump all non-system namespaces.
*/ */
if (selectTableName != NULL) if (selectTableName != NULL)
nsinfo->dump = false; nsinfo->dobj.dump = false;
else if (selectSchemaName != NULL) else if (selectSchemaName != NULL)
{ {
if (strcmp(nsinfo->dobj.name, selectSchemaName) == 0) if (strcmp(nsinfo->dobj.name, selectSchemaName) == 0)
nsinfo->dump = true; nsinfo->dobj.dump = true;
else else
nsinfo->dump = false; nsinfo->dobj.dump = false;
} }
else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 || else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
strcmp(nsinfo->dobj.name, "information_schema") == 0) strcmp(nsinfo->dobj.name, "information_schema") == 0)
nsinfo->dump = false; nsinfo->dobj.dump = false;
else else
nsinfo->dump = true; nsinfo->dobj.dump = true;
} }
/* /*
...@@ -761,20 +762,69 @@ selectDumpableTable(TableInfo *tbinfo) ...@@ -761,20 +762,69 @@ selectDumpableTable(TableInfo *tbinfo)
* tablename has been specified, dump matching table name; else, do not * tablename has been specified, dump matching table name; else, do not
* dump. * dump.
*/ */
tbinfo->dump = false; tbinfo->dobj.dump = false;
if (tbinfo->dobj.namespace->dump) if (tbinfo->dobj.namespace->dobj.dump)
tbinfo->dump = true; tbinfo->dobj.dump = true;
else if (selectTableName != NULL && else if (selectTableName != NULL &&
strcmp(tbinfo->dobj.name, selectTableName) == 0) strcmp(tbinfo->dobj.name, selectTableName) == 0)
{ {
/* If both -s and -t specified, must match both to dump */ /* If both -s and -t specified, must match both to dump */
if (selectSchemaName == NULL) if (selectSchemaName == NULL)
tbinfo->dump = true; tbinfo->dobj.dump = true;
else if (strcmp(tbinfo->dobj.namespace->dobj.name, selectSchemaName) == 0) else if (strcmp(tbinfo->dobj.namespace->dobj.name, selectSchemaName) == 0)
tbinfo->dump = true; tbinfo->dobj.dump = true;
} }
} }
/*
* selectDumpableType: policy-setting subroutine
* Mark a type as to be dumped or not
*/
static void
selectDumpableType(TypeInfo *tinfo)
{
/* Dump only types in dumpable namespaces */
if (!tinfo->dobj.namespace->dobj.dump)
tinfo->dobj.dump = false;
/* skip complex types, except for standalone composite types */
/* (note: this test should now be unnecessary) */
else if (OidIsValid(tinfo->typrelid) &&
tinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
tinfo->dobj.dump = false;
/* skip undefined placeholder types */
else if (!tinfo->isDefined)
tinfo->dobj.dump = false;
/* skip all array types that start w/ underscore */
else if ((tinfo->dobj.name[0] == '_') &&
OidIsValid(tinfo->typelem))
tinfo->dobj.dump = false;
else
tinfo->dobj.dump = true;
}
/*
* selectDumpableObject: policy-setting subroutine
* Mark a generic dumpable object as to be dumped or not
*
* Use this only for object types without a special-case routine above.
*/
static void
selectDumpableObject(DumpableObject *dobj)
{
/*
* Default policy is to dump if parent namespace is dumpable,
* or always for non-namespace-associated items.
*/
if (dobj->namespace)
dobj->dump = dobj->namespace->dobj.dump;
else
dobj->dump = true;
}
/* /*
* Dump a table's contents for loading using the COPY command * Dump a table's contents for loading using the COPY command
* - this routine is called by the Archiver when it wants the table * - this routine is called by the Archiver when it wants the table
...@@ -1130,7 +1180,7 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids) ...@@ -1130,7 +1180,7 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids)
if (tblinfo[i].relkind == RELKIND_SEQUENCE) if (tblinfo[i].relkind == RELKIND_SEQUENCE)
continue; continue;
if (tblinfo[i].dump) if (tblinfo[i].dobj.dump)
{ {
TableDataInfo *tdinfo; TableDataInfo *tdinfo;
...@@ -1749,6 +1799,7 @@ getTypes(int *numTypes) ...@@ -1749,6 +1799,7 @@ getTypes(int *numTypes)
int i; int i;
PQExpBuffer query = createPQExpBuffer(); PQExpBuffer query = createPQExpBuffer();
TypeInfo *tinfo; TypeInfo *tinfo;
ShellTypeInfo *stinfo;
int i_tableoid; int i_tableoid;
int i_oid; int i_oid;
int i_typname; int i_typname;
...@@ -1838,9 +1889,6 @@ getTypes(int *numTypes) ...@@ -1838,9 +1889,6 @@ getTypes(int *numTypes)
for (i = 0; i < ntups; i++) for (i = 0; i < ntups; i++)
{ {
Oid typoutput;
FuncInfo *funcInfo;
tinfo[i].dobj.objType = DO_TYPE; tinfo[i].dobj.objType = DO_TYPE;
tinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid)); tinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
tinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid)); tinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
...@@ -1849,12 +1897,11 @@ getTypes(int *numTypes) ...@@ -1849,12 +1897,11 @@ getTypes(int *numTypes)
tinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)), tinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
tinfo[i].dobj.catId.oid); tinfo[i].dobj.catId.oid);
tinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); tinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
tinfo[i].typinput = atooid(PQgetvalue(res, i, i_typinput));
typoutput = atooid(PQgetvalue(res, i, i_typoutput));
tinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem)); tinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
tinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid)); tinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind); tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
tinfo[i].typtype = *PQgetvalue(res, i, i_typtype); tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
tinfo[i].shellType = NULL;
/* /*
* If it's a table's rowtype, use special type code to facilitate * If it's a table's rowtype, use special type code to facilitate
...@@ -1880,28 +1927,86 @@ getTypes(int *numTypes) ...@@ -1880,28 +1927,86 @@ getTypes(int *numTypes)
else else
tinfo[i].isDefined = false; tinfo[i].isDefined = false;
/* Decide whether we want to dump it */
selectDumpableType(&tinfo[i]);
/* /*
* If it's a domain, fetch info about its constraints, if any * If it's a domain, fetch info about its constraints, if any
*/ */
tinfo[i].nDomChecks = 0; tinfo[i].nDomChecks = 0;
tinfo[i].domChecks = NULL; tinfo[i].domChecks = NULL;
if (tinfo[i].typtype == 'd') if (tinfo[i].dobj.dump && tinfo[i].typtype == 'd')
getDomainConstraints(&(tinfo[i])); getDomainConstraints(&(tinfo[i]));
/* /*
* Make sure there are dependencies from the type to its input and * If it's a base type, make a DumpableObject representing a shell
* output functions. (We don't worry about typsend, typreceive, or * definition of the type. We will need to dump that ahead of the
* typanalyze since those are only valid in 7.4 and later, wherein the * I/O functions for the type.
* standard dependency mechanism will pick them up.) *
* Note: the shell type doesn't have a catId. You might think it
* should copy the base type's catId, but then it might capture
* the pg_depend entries for the type, which we don't want.
*/ */
funcInfo = findFuncByOid(tinfo[i].typinput); if (tinfo[i].dobj.dump && tinfo[i].typtype == 'b')
if (funcInfo) {
stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
stinfo->dobj.objType = DO_SHELL_TYPE;
stinfo->dobj.catId = nilCatalogId;
AssignDumpId(&stinfo->dobj);
stinfo->dobj.name = strdup(tinfo[i].dobj.name);
stinfo->dobj.namespace = tinfo[i].dobj.namespace;
stinfo->baseType = &(tinfo[i]);
tinfo[i].shellType = stinfo;
/*
* Initially mark the shell type as not to be dumped. We'll
* only dump it if the I/O functions need to be dumped; this
* is taken care of while sorting dependencies.
*/
stinfo->dobj.dump = false;
/*
* However, if dumping from pre-7.3, there will be no dependency
* info so we have to fake it here. We only need to worry about
* typinput and typoutput since the other functions only exist
* post-7.3.
*/
if (g_fout->remoteVersion < 70300)
{
Oid typinput;
Oid typoutput;
FuncInfo *funcInfo;
typinput = atooid(PQgetvalue(res, i, i_typinput));
typoutput = atooid(PQgetvalue(res, i, i_typoutput));
funcInfo = findFuncByOid(typinput);
if (funcInfo && funcInfo->dobj.dump)
{
/* base type depends on function */
addObjectDependency(&tinfo[i].dobj, addObjectDependency(&tinfo[i].dobj,
funcInfo->dobj.dumpId); funcInfo->dobj.dumpId);
/* function depends on shell type */
addObjectDependency(&funcInfo->dobj,
stinfo->dobj.dumpId);
/* mark shell type as to be dumped */
stinfo->dobj.dump = true;
}
funcInfo = findFuncByOid(typoutput); funcInfo = findFuncByOid(typoutput);
if (funcInfo) if (funcInfo && funcInfo->dobj.dump)
{
/* base type depends on function */
addObjectDependency(&tinfo[i].dobj, addObjectDependency(&tinfo[i].dobj,
funcInfo->dobj.dumpId); funcInfo->dobj.dumpId);
/* function depends on shell type */
addObjectDependency(&funcInfo->dobj,
stinfo->dobj.dumpId);
/* mark shell type as to be dumped */
stinfo->dobj.dump = true;
}
}
}
if (strlen(tinfo[i].rolname) == 0 && tinfo[i].isDefined) if (strlen(tinfo[i].rolname) == 0 && tinfo[i].isDefined)
write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n", write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
...@@ -2004,6 +2109,9 @@ getOperators(int *numOprs) ...@@ -2004,6 +2109,9 @@ getOperators(int *numOprs)
oprinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); oprinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode)); oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
/* Decide whether we want to dump it */
selectDumpableObject(&(oprinfo[i].dobj));
if (strlen(oprinfo[i].rolname) == 0) if (strlen(oprinfo[i].rolname) == 0)
write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n", write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
oprinfo[i].dobj.name); oprinfo[i].dobj.name);
...@@ -2082,6 +2190,9 @@ getConversions(int *numConversions) ...@@ -2082,6 +2190,9 @@ getConversions(int *numConversions)
convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)), convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
convinfo[i].dobj.catId.oid); convinfo[i].dobj.catId.oid);
convinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); convinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
/* Decide whether we want to dump it */
selectDumpableObject(&(convinfo[i].dobj));
} }
PQclear(res); PQclear(res);
...@@ -2170,6 +2281,9 @@ getOpclasses(int *numOpclasses) ...@@ -2170,6 +2281,9 @@ getOpclasses(int *numOpclasses)
opcinfo[i].dobj.catId.oid); opcinfo[i].dobj.catId.oid);
opcinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); opcinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
/* Decide whether we want to dump it */
selectDumpableObject(&(opcinfo[i].dobj));
if (g_fout->remoteVersion >= 70300) if (g_fout->remoteVersion >= 70300)
{ {
if (strlen(opcinfo[i].rolname) == 0) if (strlen(opcinfo[i].rolname) == 0)
...@@ -2290,6 +2404,9 @@ getAggregates(int *numAggs) ...@@ -2290,6 +2404,9 @@ getAggregates(int *numAggs)
agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl)); agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl));
agginfo[i].anybasetype = false; /* computed when it's dumped */ agginfo[i].anybasetype = false; /* computed when it's dumped */
agginfo[i].fmtbasetype = NULL; /* computed when it's dumped */ agginfo[i].fmtbasetype = NULL; /* computed when it's dumped */
/* Decide whether we want to dump it */
selectDumpableObject(&(agginfo[i].aggfn.dobj));
} }
PQclear(res); PQclear(res);
...@@ -2418,6 +2535,9 @@ getFuncs(int *numFuncs) ...@@ -2418,6 +2535,9 @@ getFuncs(int *numFuncs)
finfo[i].argtypes, finfo[i].nargs); finfo[i].argtypes, finfo[i].nargs);
} }
/* Decide whether we want to dump it */
selectDumpableObject(&(finfo[i].dobj));
if (strlen(finfo[i].rolname) == 0) if (strlen(finfo[i].rolname) == 0)
write_msg(NULL, write_msg(NULL,
"WARNING: owner of function \"%s\" appears to be invalid\n", "WARNING: owner of function \"%s\" appears to be invalid\n",
...@@ -2681,12 +2801,12 @@ getTables(int *numTables) ...@@ -2681,12 +2801,12 @@ getTables(int *numTables)
* their owning table's dump flag to them below. * their owning table's dump flag to them below.
*/ */
if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE) if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
tblinfo[i].dump = false; tblinfo[i].dobj.dump = false;
else if (OidIsValid(tblinfo[i].owning_tab)) else if (OidIsValid(tblinfo[i].owning_tab))
tblinfo[i].dump = false; tblinfo[i].dobj.dump = false;
else else
selectDumpableTable(&tblinfo[i]); selectDumpableTable(&tblinfo[i]);
tblinfo[i].interesting = tblinfo[i].dump; tblinfo[i].interesting = tblinfo[i].dobj.dump;
/* /*
* Read-lock target tables to make sure they aren't DROPPED or altered * Read-lock target tables to make sure they aren't DROPPED or altered
...@@ -2699,7 +2819,7 @@ getTables(int *numTables) ...@@ -2699,7 +2819,7 @@ getTables(int *numTables)
* NOTE: it'd be kinda nice to lock views and sequences too, not only * NOTE: it'd be kinda nice to lock views and sequences too, not only
* plain tables, but the backend doesn't presently allow that. * plain tables, but the backend doesn't presently allow that.
*/ */
if (tblinfo[i].dump && tblinfo[i].relkind == RELKIND_RELATION) if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
{ {
resetPQExpBuffer(lockquery); resetPQExpBuffer(lockquery);
appendPQExpBuffer(lockquery, appendPQExpBuffer(lockquery,
...@@ -2832,7 +2952,8 @@ getIndexes(TableInfo tblinfo[], int numTables) ...@@ -2832,7 +2952,8 @@ getIndexes(TableInfo tblinfo[], int numTables)
if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex) if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
continue; continue;
if (!tbinfo->dump) /* Ignore indexes of tables not to be dumped */
if (!tbinfo->dobj.dump)
continue; continue;
if (g_verbose) if (g_verbose)
...@@ -3068,7 +3189,7 @@ getConstraints(TableInfo tblinfo[], int numTables) ...@@ -3068,7 +3189,7 @@ getConstraints(TableInfo tblinfo[], int numTables)
{ {
TableInfo *tbinfo = &tblinfo[i]; TableInfo *tbinfo = &tblinfo[i];
if (tbinfo->ntrig == 0 || !tbinfo->dump) if (tbinfo->ntrig == 0 || !tbinfo->dobj.dump)
continue; continue;
if (g_verbose) if (g_verbose)
...@@ -3290,6 +3411,7 @@ getRules(int *numRules) ...@@ -3290,6 +3411,7 @@ getRules(int *numRules)
exit_nicely(); exit_nicely();
} }
ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace; ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type)); ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't'; ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
if (ruleinfo[i].ruletable) if (ruleinfo[i].ruletable)
...@@ -3361,7 +3483,7 @@ getTriggers(TableInfo tblinfo[], int numTables) ...@@ -3361,7 +3483,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
{ {
TableInfo *tbinfo = &tblinfo[i]; TableInfo *tbinfo = &tblinfo[i];
if (tbinfo->ntrig == 0 || !tbinfo->dump) if (tbinfo->ntrig == 0 || !tbinfo->dobj.dump)
continue; continue;
if (g_verbose) if (g_verbose)
...@@ -3987,6 +4109,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables) ...@@ -3987,6 +4109,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
attrdefs[j].dobj.name = strdup(tbinfo->dobj.name); attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
attrdefs[j].dobj.namespace = tbinfo->dobj.namespace; attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
attrdefs[j].dobj.dump = tbinfo->dobj.dump;
/* /*
* Defaults on a VIEW must always be dumped as separate ALTER * Defaults on a VIEW must always be dumped as separate ALTER
* TABLE commands. Defaults on regular tables are dumped as * TABLE commands. Defaults on regular tables are dumped as
...@@ -4117,6 +4241,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables) ...@@ -4117,6 +4241,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
constrs[j].coninherited = false; constrs[j].coninherited = false;
constrs[j].separate = false; constrs[j].separate = false;
constrs[j].dobj.dump = tbinfo->dobj.dump;
/* /*
* Mark the constraint as needing to appear before the table * Mark the constraint as needing to appear before the table
* --- this is so that any other dependencies of the * --- this is so that any other dependencies of the
...@@ -4167,7 +4293,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) ...@@ -4167,7 +4293,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
*/ */
tbinfo->attisserial[j] = true; tbinfo->attisserial[j] = true;
seqinfo->interesting = tbinfo->interesting; seqinfo->interesting = tbinfo->interesting;
seqinfo->dump = tbinfo->dump; seqinfo->dobj.dump = tbinfo->dobj.dump;
break; break;
} }
} }
...@@ -4513,6 +4639,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj) ...@@ -4513,6 +4639,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
case DO_TYPE: case DO_TYPE:
dumpType(fout, (TypeInfo *) dobj); dumpType(fout, (TypeInfo *) dobj);
break; break;
case DO_SHELL_TYPE:
dumpShellType(fout, (ShellTypeInfo *) dobj);
break;
case DO_FUNC: case DO_FUNC:
dumpFunc(fout, (FuncInfo *) dobj); dumpFunc(fout, (FuncInfo *) dobj);
break; break;
...@@ -4589,8 +4718,8 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo) ...@@ -4589,8 +4718,8 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
PQExpBuffer delq; PQExpBuffer delq;
char *qnspname; char *qnspname;
/* skip if not to be dumped */ /* Skip if not to be dumped */
if (!nspinfo->dump || dataOnly) if (!nspinfo->dobj.dump || dataOnly)
return; return;
/* don't dump dummy namespace from pre-7.3 source */ /* don't dump dummy namespace from pre-7.3 source */
...@@ -4638,23 +4767,8 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo) ...@@ -4638,23 +4767,8 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
static void static void
dumpType(Archive *fout, TypeInfo *tinfo) dumpType(Archive *fout, TypeInfo *tinfo)
{ {
/* Dump only types in dumpable namespaces */ /* Skip if not to be dumped */
if (!tinfo->dobj.namespace->dump || dataOnly) if (!tinfo->dobj.dump || dataOnly)
return;
/* skip complex types, except for standalone composite types */
/* (note: this test should now be unnecessary) */
if (OidIsValid(tinfo->typrelid) &&
tinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
return;
/* skip undefined placeholder types */
if (!tinfo->isDefined)
return;
/* skip all array types that start w/ underscore */
if ((tinfo->dobj.name[0] == '_') &&
OidIsValid(tinfo->typelem))
return; return;
/* Dump out in proper style */ /* Dump out in proper style */
...@@ -4844,7 +4958,10 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) ...@@ -4844,7 +4958,10 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
typdefault = NULL; typdefault = NULL;
/* /*
* DROP must be fully qualified in case same name appears in pg_catalog * DROP must be fully qualified in case same name appears in pg_catalog.
* The reason we include CASCADE is that the circular dependency between
* the type and its I/O functions makes it impossible to drop the type
* any other way.
*/ */
appendPQExpBuffer(delq, "DROP TYPE %s.", appendPQExpBuffer(delq, "DROP TYPE %s.",
fmtId(tinfo->dobj.namespace->dobj.name)); fmtId(tinfo->dobj.namespace->dobj.name));
...@@ -5162,6 +5279,47 @@ dumpCompositeType(Archive *fout, TypeInfo *tinfo) ...@@ -5162,6 +5279,47 @@ dumpCompositeType(Archive *fout, TypeInfo *tinfo)
destroyPQExpBuffer(query); destroyPQExpBuffer(query);
} }
/*
* dumpShellType
* writes out to fout the queries to create a shell type
*
* We dump a shell definition in advance of the I/O functions for the type.
*/
static void
dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
{
PQExpBuffer q;
/* Skip if not to be dumped */
if (!stinfo->dobj.dump || dataOnly)
return;
q = createPQExpBuffer();
/*
* Note the lack of a DROP command for the shell type; any required DROP
* is driven off the base type entry, instead. This interacts with
* _printTocEntry()'s use of the presence of a DROP command to decide
* whether an entry needs an ALTER OWNER command. We don't want to
* alter the shell type's owner immediately on creation; that should
* happen only after it's filled in, otherwise the backend complains.
*/
appendPQExpBuffer(q, "CREATE TYPE %s;\n",
fmtId(stinfo->dobj.name));
ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
stinfo->dobj.name,
stinfo->dobj.namespace->dobj.name,
NULL,
stinfo->baseType->rolname, false,
"SHELL TYPE", q->data, "", NULL,
stinfo->dobj.dependencies, stinfo->dobj.nDeps,
NULL, NULL);
destroyPQExpBuffer(q);
}
/* /*
* Determine whether we want to dump definitions for procedural languages. * Determine whether we want to dump definitions for procedural languages.
* Since the languages themselves don't have schemas, we can't rely on * Since the languages themselves don't have schemas, we can't rely on
...@@ -5213,13 +5371,13 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) ...@@ -5213,13 +5371,13 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
*/ */
funcInfo = findFuncByOid(plang->lanplcallfoid); funcInfo = findFuncByOid(plang->lanplcallfoid);
if (funcInfo != NULL && !funcInfo->dobj.namespace->dump) if (funcInfo != NULL && !funcInfo->dobj.dump)
funcInfo = NULL; /* treat not-dumped same as not-found */ funcInfo = NULL; /* treat not-dumped same as not-found */
if (OidIsValid(plang->lanvalidator)) if (OidIsValid(plang->lanvalidator))
{ {
validatorInfo = findFuncByOid(plang->lanvalidator); validatorInfo = findFuncByOid(plang->lanvalidator);
if (validatorInfo != NULL && !validatorInfo->dobj.namespace->dump) if (validatorInfo != NULL && !validatorInfo->dobj.dump)
validatorInfo = NULL; validatorInfo = NULL;
} }
...@@ -5434,8 +5592,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) ...@@ -5434,8 +5592,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
char **argmodes = NULL; char **argmodes = NULL;
char **argnames = NULL; char **argnames = NULL;
/* Dump only funcs in dumpable namespaces */ /* Skip if not to be dumped */
if (!finfo->dobj.namespace->dump || dataOnly) if (!finfo->dobj.dump || dataOnly)
return; return;
query = createPQExpBuffer(); query = createPQExpBuffer();
...@@ -5727,9 +5885,8 @@ dumpCast(Archive *fout, CastInfo *cast) ...@@ -5727,9 +5885,8 @@ dumpCast(Archive *fout, CastInfo *cast)
/* /*
* As per discussion we dump casts if one or more of the underlying * As per discussion we dump casts if one or more of the underlying
* objects (the conversion function and the two data types) are not * objects (the conversion function and the two data types) are not
* builtin AND if all of the non-builtin objects namespaces are included * builtin AND if all of the non-builtin objects are included in the dump.
* in the dump. Builtin meaning, the namespace name does not start with * Builtin meaning, the namespace name does not start with "pg_".
* "pg_".
*/ */
sourceInfo = findTypeByOid(cast->castsource); sourceInfo = findTypeByOid(cast->castsource);
targetInfo = findTypeByOid(cast->casttarget); targetInfo = findTypeByOid(cast->casttarget);
...@@ -5747,25 +5904,25 @@ dumpCast(Archive *fout, CastInfo *cast) ...@@ -5747,25 +5904,25 @@ dumpCast(Archive *fout, CastInfo *cast)
return; return;
/* /*
* Skip cast if function isn't from pg_ and that namespace is not dumped. * Skip cast if function isn't from pg_ and is not to be dumped.
*/ */
if (funcInfo && if (funcInfo &&
strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 && strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
!funcInfo->dobj.namespace->dump) !funcInfo->dobj.dump)
return; return;
/* /*
* Same for the Source type * Same for the source type
*/ */
if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 && if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
!sourceInfo->dobj.namespace->dump) !sourceInfo->dobj.dump)
return; return;
/* /*
* and the target type. * and the target type.
*/ */
if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 && if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
!targetInfo->dobj.namespace->dump) !targetInfo->dobj.dump)
return; return;
/* Make sure we are in proper schema (needed for getFormattedTypeName) */ /* Make sure we are in proper schema (needed for getFormattedTypeName) */
...@@ -5870,8 +6027,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo) ...@@ -5870,8 +6027,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
char *oprltcmpop; char *oprltcmpop;
char *oprgtcmpop; char *oprgtcmpop;
/* Dump only operators in dumpable namespaces */ /* Skip if not to be dumped */
if (!oprinfo->dobj.namespace->dump || dataOnly) if (!oprinfo->dobj.dump || dataOnly)
return; return;
/* /*
...@@ -6220,8 +6377,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) ...@@ -6220,8 +6377,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
bool needComma; bool needComma;
int i; int i;
/* Dump only opclasses in dumpable namespaces */ /* Skip if not to be dumped */
if (!opcinfo->dobj.namespace->dump || dataOnly) if (!opcinfo->dobj.dump || dataOnly)
return; return;
/* /*
...@@ -6428,8 +6585,8 @@ dumpConversion(Archive *fout, ConvInfo *convinfo) ...@@ -6428,8 +6585,8 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
const char *conproc; const char *conproc;
bool condefault; bool condefault;
/* Dump only conversions in dumpable namespaces */ /* Skip if not to be dumped */
if (!convinfo->dobj.namespace->dump || dataOnly) if (!convinfo->dobj.dump || dataOnly)
return; return;
query = createPQExpBuffer(); query = createPQExpBuffer();
...@@ -6582,8 +6739,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo) ...@@ -6582,8 +6739,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
const char *agginitval; const char *agginitval;
bool convertok; bool convertok;
/* Dump only aggs in dumpable namespaces */ /* Skip if not to be dumped */
if (!agginfo->aggfn.dobj.namespace->dump || dataOnly) if (!agginfo->aggfn.dobj.dump || dataOnly)
return; return;
query = createPQExpBuffer(); query = createPQExpBuffer();
...@@ -6855,7 +7012,7 @@ dumpTable(Archive *fout, TableInfo *tbinfo) ...@@ -6855,7 +7012,7 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
{ {
char *namecopy; char *namecopy;
if (tbinfo->dump) if (tbinfo->dobj.dump)
{ {
if (tbinfo->relkind == RELKIND_SEQUENCE) if (tbinfo->relkind == RELKIND_SEQUENCE)
dumpSequence(fout, tbinfo); dumpSequence(fout, tbinfo);
...@@ -7178,7 +7335,7 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo) ...@@ -7178,7 +7335,7 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
PQExpBuffer delq; PQExpBuffer delq;
/* Only print it if "separate" mode is selected */ /* Only print it if "separate" mode is selected */
if (!tbinfo->dump || !adinfo->separate || dataOnly) if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
return; return;
/* Don't print inherited or serial defaults, either */ /* Don't print inherited or serial defaults, either */
...@@ -7331,9 +7488,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) ...@@ -7331,9 +7488,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
PQExpBuffer q; PQExpBuffer q;
PQExpBuffer delq; PQExpBuffer delq;
if (dataOnly) /* Skip if not to be dumped */
return; if (!coninfo->dobj.dump || dataOnly)
if (tbinfo && !tbinfo->dump)
return; return;
q = createPQExpBuffer(); q = createPQExpBuffer();
...@@ -7477,8 +7633,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) ...@@ -7477,8 +7633,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
/* CHECK constraint on a domain */ /* CHECK constraint on a domain */
TypeInfo *tinfo = coninfo->condomain; TypeInfo *tinfo = coninfo->condomain;
/* Ignore if not to be dumped separately, or if not dumping domain */ /* Ignore if not to be dumped separately */
if (coninfo->separate && tinfo->dobj.namespace->dump) if (coninfo->separate)
{ {
appendPQExpBuffer(q, "ALTER DOMAIN %s\n", appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
fmtId(tinfo->dobj.name)); fmtId(tinfo->dobj.name));
...@@ -7995,10 +8151,8 @@ dumpRule(Archive *fout, RuleInfo *rinfo) ...@@ -7995,10 +8151,8 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
PQExpBuffer delcmd; PQExpBuffer delcmd;
PGresult *res; PGresult *res;
/* /* Skip if not to be dumped */
* Ignore rules for not-to-be-dumped tables if (!rinfo->dobj.dump || dataOnly)
*/
if (tbinfo == NULL || !tbinfo->dump || dataOnly)
return; return;
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, 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/pg_dump.h,v 1.123 2005/12/03 21:06:18 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.124 2006/03/02 01:18:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -62,6 +62,7 @@ typedef enum ...@@ -62,6 +62,7 @@ typedef enum
/* When modifying this enum, update priority tables in pg_dump_sort.c! */ /* When modifying this enum, update priority tables in pg_dump_sort.c! */
DO_NAMESPACE, DO_NAMESPACE,
DO_TYPE, DO_TYPE,
DO_SHELL_TYPE,
DO_FUNC, DO_FUNC,
DO_AGG, DO_AGG,
DO_OPERATOR, DO_OPERATOR,
...@@ -89,6 +90,7 @@ typedef struct _dumpableObject ...@@ -89,6 +90,7 @@ typedef struct _dumpableObject
DumpId dumpId; /* assigned by AssignDumpId() */ DumpId dumpId; /* assigned by AssignDumpId() */
char *name; /* object name (should never be NULL) */ char *name; /* object name (should never be NULL) */
struct _namespaceInfo *namespace; /* containing namespace, or NULL */ struct _namespaceInfo *namespace; /* containing namespace, or NULL */
bool dump; /* true if we want to dump this object */
DumpId *dependencies; /* dumpIds of objects this one depends on */ DumpId *dependencies; /* dumpIds of objects this one depends on */
int nDeps; /* number of valid dependencies */ int nDeps; /* number of valid dependencies */
int allocDeps; /* allocated size of dependencies[] */ int allocDeps; /* allocated size of dependencies[] */
...@@ -99,7 +101,6 @@ typedef struct _namespaceInfo ...@@ -99,7 +101,6 @@ typedef struct _namespaceInfo
DumpableObject dobj; DumpableObject dobj;
char *rolname; /* name of owner, or empty string */ char *rolname; /* name of owner, or empty string */
char *nspacl; char *nspacl;
bool dump; /* true if need to dump definition */
} NamespaceInfo; } NamespaceInfo;
typedef struct _typeInfo typedef struct _typeInfo
...@@ -111,18 +112,26 @@ typedef struct _typeInfo ...@@ -111,18 +112,26 @@ typedef struct _typeInfo
* produce something different than typname * produce something different than typname
*/ */
char *rolname; /* name of owner, or empty string */ char *rolname; /* name of owner, or empty string */
Oid typinput;
Oid typelem; Oid typelem;
Oid typrelid; Oid typrelid;
char typrelkind; /* 'r', 'v', 'c', etc */ char typrelkind; /* 'r', 'v', 'c', etc */
char typtype; /* 'b', 'c', etc */ char typtype; /* 'b', 'c', etc */
bool isArray; /* true if user-defined array type */ bool isArray; /* true if user-defined array type */
bool isDefined; /* true if typisdefined */ bool isDefined; /* true if typisdefined */
/* If it's a dumpable base type, we create a "shell type" entry for it */
struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */
/* If it's a domain, we store links to its constraints here: */ /* If it's a domain, we store links to its constraints here: */
int nDomChecks; int nDomChecks;
struct _constraintInfo *domChecks; struct _constraintInfo *domChecks;
} TypeInfo; } TypeInfo;
typedef struct _shellTypeInfo
{
DumpableObject dobj;
TypeInfo *baseType; /* back link to associated base type */
} ShellTypeInfo;
typedef struct _funcInfo typedef struct _funcInfo
{ {
DumpableObject dobj; DumpableObject dobj;
...@@ -181,7 +190,6 @@ typedef struct _tableInfo ...@@ -181,7 +190,6 @@ typedef struct _tableInfo
int owning_col; /* attr # of column owning sequence */ int owning_col; /* attr # of column owning sequence */
bool interesting; /* true if need to collect more data */ bool interesting; /* true if need to collect more data */
bool dump; /* true if we want to dump it */
/* /*
* These fields are computed only if we decide the table is interesting * These fields are computed only if we decide the table is interesting
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.12 2005/11/22 18:17:29 momjian Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.13 2006/03/02 01:18:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,6 +29,7 @@ static const int oldObjectTypePriority[] = ...@@ -29,6 +29,7 @@ static const int oldObjectTypePriority[] =
{ {
1, /* DO_NAMESPACE */ 1, /* DO_NAMESPACE */
2, /* DO_TYPE */ 2, /* DO_TYPE */
2, /* DO_SHELL_TYPE */
2, /* DO_FUNC */ 2, /* DO_FUNC */
3, /* DO_AGG */ 3, /* DO_AGG */
3, /* DO_OPERATOR */ 3, /* DO_OPERATOR */
...@@ -57,6 +58,7 @@ static const int newObjectTypePriority[] = ...@@ -57,6 +58,7 @@ static const int newObjectTypePriority[] =
{ {
1, /* DO_NAMESPACE */ 1, /* DO_NAMESPACE */
3, /* DO_TYPE */ 3, /* DO_TYPE */
3, /* DO_SHELL_TYPE */
4, /* DO_FUNC */ 4, /* DO_FUNC */
5, /* DO_AGG */ 5, /* DO_AGG */
6, /* DO_OPERATOR */ 6, /* DO_OPERATOR */
...@@ -602,35 +604,25 @@ findLoop(DumpableObject *obj, ...@@ -602,35 +604,25 @@ findLoop(DumpableObject *obj,
/* /*
* A user-defined datatype will have a dependency loop with each of its * A user-defined datatype will have a dependency loop with each of its
* I/O functions (since those have the datatype as input or output). * I/O functions (since those have the datatype as input or output).
* We want the dump ordering to be the input function, then any other * Break the loop and make the I/O function depend on the associated
* I/O functions, then the datatype. So we break the circularity in * shell type, instead.
* favor of the functions, and add a dependency from any non-input
* function to the input function.
*/ */
static void static void
repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj) repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
{ {
TypeInfo *typeInfo = (TypeInfo *) typeobj; TypeInfo *typeInfo = (TypeInfo *) typeobj;
FuncInfo *inputFuncInfo;
/* remove function's dependency on type */ /* remove function's dependency on type */
removeObjectDependency(funcobj, typeobj->dumpId); removeObjectDependency(funcobj, typeobj->dumpId);
/* if this isn't the input function, make it depend on same */ /* add function's dependency on shell type, instead */
if (funcobj->catId.oid == typeInfo->typinput) if (typeInfo->shellType)
return; /* it is the input function */ {
inputFuncInfo = findFuncByOid(typeInfo->typinput); addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
if (inputFuncInfo == NULL) /* Mark shell type as to be dumped if any I/O function is */
return; if (funcobj->dump)
addObjectDependency(funcobj, inputFuncInfo->dobj.dumpId); typeInfo->shellType->dobj.dump = true;
}
/*
* Make sure the input function's dependency on type gets removed too; if
* it hasn't been done yet, we'd end up with loops involving the type and
* two or more functions, which repairDependencyLoop() is not smart enough
* to handle.
*/
removeObjectDependency(&inputFuncInfo->dobj, typeobj->dumpId);
} }
/* /*
...@@ -980,6 +972,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize) ...@@ -980,6 +972,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
"TYPE %s (ID %d OID %u)", "TYPE %s (ID %d OID %u)",
obj->name, obj->dumpId, obj->catId.oid); obj->name, obj->dumpId, obj->catId.oid);
return; return;
case DO_SHELL_TYPE:
snprintf(buf, bufsize,
"SHELL TYPE %s (ID %d OID %u)",
obj->name, obj->dumpId, obj->catId.oid);
return;
case DO_FUNC: case DO_FUNC:
snprintf(buf, bufsize, snprintf(buf, bufsize,
"FUNCTION %s (ID %d OID %u)", "FUNCTION %s (ID %d OID %u)",
......
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