* by PostgreSQL
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.443 2006/08/01 18:05:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.447 2006/08/21 00:57:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
- objnameArg *this_obj_name = NULL;
+ objnameArg *this_obj_name, *schemaList_tail = NULL, *tableList_tail = NULL;
int c;
const char *filename = NULL;
const char *format = "p";
while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:uU:vWxX:Z:",
long_options, &optindex)) != -1)
{
- objnameArg *schemaList_tail = NULL, *tableList_tail = NULL;
-
switch (c)
{
case 'a': /* Dump data only */
/* Check schema selection flags */
resetPQExpBuffer(query);
switch_include_exclude = true;
+
for (this_obj_name = schemaList; this_obj_name; this_obj_name = this_obj_name->next)
{
if (switch_include_exclude)
{
/* Special case for when -N is the first argument */
if (this_obj_name == schemaList && !this_obj_name->is_include)
- appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_namespace EXCEPT\n");
+ appendPQExpBuffer(query,
+ "SELECT oid FROM pg_catalog.pg_namespace "
+ "WHERE nspname NOT LIKE 'pg_%%' AND "
+ " nspname != 'information_schema' EXCEPT\n");
appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_namespace WHERE");
}
/* Check table selection flags */
resetPQExpBuffer(query);
switch_include_exclude = true;
+
for (this_obj_name = tableList; this_obj_name; this_obj_name = this_obj_name->next)
{
if (switch_include_exclude)
{
/* Special case for when -T is the first argument */
if (this_obj_name == tableList && !this_obj_name->is_include && !strlen(query->data))
- appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_class WHERE relkind='r' EXCEPT\n");
+ appendPQExpBuffer(query,
+ "SELECT pg_class.oid FROM pg_catalog.pg_class, pg_catalog.pg_namespace "
+ "WHERE relkind='r' AND "
+ " relnamespace = pg_namespace.oid AND "
+ " nspname NOT LIKE 'pg_%%' AND "
+ " nspname != 'information_schema' EXCEPT\n");
appendPQExpBuffer(query, "SELECT oid FROM pg_catalog.pg_class WHERE relkind='r' AND (");
}
* namespaces. If specific namespaces are being dumped, dump just
* those namespaces. Otherwise, dump all non-system namespaces.
*/
+ nsinfo->dobj.dump = false;
+
if (matchingTables != NULL)
- nsinfo->dobj.dump = false;
+ /* false */;
else if (matchingSchemas != NULL)
{
- char *searchname = NULL;
- searchname = malloc(20);
- sprintf(searchname, " %d ", nsinfo->dobj.catId.oid);
- if (strstr(matchingSchemas, searchname) != NULL)
+ char *search_oid = malloc(20);
+
+ sprintf(search_oid, " %d ", nsinfo->dobj.catId.oid);
+ if (strstr(matchingSchemas, search_oid) != NULL)
nsinfo->dobj.dump = true;
- free(searchname);
+
+ free(search_oid);
}
- else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
- strcmp(nsinfo->dobj.name, "information_schema") == 0)
- nsinfo->dobj.dump = false;
- else
+ /* The server prevents users from creating pg_ schemas */
+ else if (strncmp(nsinfo->dobj.name, "pg_", 3) != 0 &&
+ strcmp(nsinfo->dobj.name, "information_schema") != 0)
nsinfo->dobj.dump = true;
}
* dump.
*/
tbinfo->dobj.dump = false;
- if (tbinfo->dobj.namespace->dobj.dump || matchingTables == NULL)
- tbinfo->dobj.dump = true;
+
+ if (matchingTables == NULL)
+ {
+ if (tbinfo->dobj.namespace->dobj.dump)
+ tbinfo->dobj.dump = true;
+ }
else
{
- char *searchname = NULL;
- searchname = malloc(20);
- sprintf(searchname, " %d ", tbinfo->dobj.catId.oid);
- if (strstr(matchingTables, searchname) != NULL)
+ char *search_oid = malloc(20);
+
+ sprintf(search_oid, " %d ", tbinfo->dobj.catId.oid);
+ if (strstr(matchingTables, search_oid) != NULL)
tbinfo->dobj.dump = true;
- free(searchname);
+
+ free(search_oid);
}
}
* Note: in this phase we should collect only a minimal amount of
* information about each table, basically just enough to decide if it is
* interesting. We must fetch all tables in this phase because otherwise
- * we cannot correctly identify inherited columns, serial columns, etc.
+ * we cannot correctly identify inherited columns, owned sequences, etc.
*/
if (g_fout->remoteVersion >= 80200)
{
/*
* Left join to pick up dependency info linking sequences to their
- * serial column, if any
+ * owning column, if any (note this dependency is AUTO as of 8.2)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, relname, "
"(c.relkind = '%c' and "
"d.classid = c.tableoid and d.objid = c.oid and "
"d.objsubid = 0 and "
- "d.refclassid = c.tableoid and d.deptype = 'i') "
+ "d.refclassid = c.tableoid and d.deptype = 'a') "
"where relkind in ('%c', '%c', '%c', '%c') "
"order by c.oid",
username_subquery,
{
/*
* Left join to pick up dependency info linking sequences to their
- * serial column, if any
+ * owning column, if any
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, relname, "
{
/*
* Left join to pick up dependency info linking sequences to their
- * serial column, if any
+ * owning column, if any
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, relname, "
/* other fields were zeroed above */
/*
- * Decide whether we want to dump this table. Sequences owned by
- * serial columns are never dumpable on their own; we will transpose
- * their owning table's dump flag to them below.
+ * Decide whether we want to dump this table.
*/
if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
tblinfo[i].dobj.dump = false;
- else if (OidIsValid(tblinfo[i].owning_tab))
- tblinfo[i].dobj.dump = false;
else
selectDumpableTable(&tblinfo[i]);
tblinfo[i].interesting = tblinfo[i].dobj.dump;
}
PQclear(res);
+
+ /*
+ * Force sequences that are "owned" by table columns to be dumped
+ * whenever their owning table is being dumped.
+ */
+ for (i = 0; i < ntups; i++)
+ {
+ TableInfo *seqinfo = &tblinfo[i];
+ int j;
+
+ if (!OidIsValid(seqinfo->owning_tab))
+ continue; /* not an owned sequence */
+ if (seqinfo->dobj.dump)
+ continue; /* no need to search */
+
+ /* can't use findTableByOid yet, unfortunately */
+ for (j = 0; j < ntups; j++)
+ {
+ if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
+ {
+ if (tblinfo[j].dobj.dump)
+ {
+ seqinfo->interesting = true;
+ seqinfo->dobj.dump = true;
+ }
+ break;
+ }
+ }
+ }
+
destroyPQExpBuffer(query);
destroyPQExpBuffer(delqry);
destroyPQExpBuffer(lockquery);
getTableAttrs(TableInfo *tblinfo, int numTables)
{
int i,
- j,
- k;
+ j;
PQExpBuffer q = createPQExpBuffer();
int i_attnum;
int i_attname;
tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
- tbinfo->attisserial = (bool *) malloc(ntups * sizeof(bool));
tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
- tbinfo->attisserial[j] = false; /* fix below */
tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
tbinfo->attrdefs[j] = NULL; /* fix below */
if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
}
PQclear(res);
}
-
- /*
- * Check to see if any columns are serial columns. Our first quick
- * filter is that it must be integer or bigint with a default. If so,
- * we scan to see if we found a sequence linked to this column. If we
- * did, mark the column and sequence appropriately.
- */
- for (j = 0; j < ntups; j++)
- {
- /*
- * Note assumption that format_type will show these types as
- * exactly "integer" and "bigint" regardless of schema path. This
- * is correct in 7.3 but needs to be watched.
- */
- if (strcmp(tbinfo->atttypnames[j], "integer") != 0 &&
- strcmp(tbinfo->atttypnames[j], "bigint") != 0)
- continue;
- if (tbinfo->attrdefs[j] == NULL)
- continue;
- for (k = 0; k < numTables; k++)
- {
- TableInfo *seqinfo = &tblinfo[k];
-
- if (OidIsValid(seqinfo->owning_tab) &&
- seqinfo->owning_tab == tbinfo->dobj.catId.oid &&
- seqinfo->owning_col == j + 1)
- {
- /*
- * Found a match. Copy the table's interesting and
- * dumpable flags to the sequence.
- */
- tbinfo->attisserial[j] = true;
- seqinfo->interesting = tbinfo->interesting;
- seqinfo->dobj.dump = tbinfo->dobj.dump;
- break;
- }
- }
- }
}
destroyPQExpBuffer(q);
* Skip this cast if all objects are from pg_
*/
if ((funcInfo == NULL ||
- strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
+ strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
return;
/* Attribute type */
if (g_fout->remoteVersion >= 70100)
{
- char *typname = tbinfo->atttypnames[j];
-
- if (tbinfo->attisserial[j])
- {
- if (strcmp(typname, "integer") == 0)
- typname = "serial";
- else if (strcmp(typname, "bigint") == 0)
- typname = "bigserial";
- }
- appendPQExpBuffer(q, "%s", typname);
+ appendPQExpBuffer(q, "%s",
+ tbinfo->atttypnames[j]);
}
else
{
}
/*
- * Default value --- suppress if inherited, serial, or to be
+ * Default value --- suppress if inherited or to be
* printed separately.
*/
if (tbinfo->attrdefs[j] != NULL &&
!tbinfo->inhAttrDef[j] &&
- !tbinfo->attisserial[j] &&
!tbinfo->attrdefs[j]->separate)
appendPQExpBuffer(q, " DEFAULT %s",
tbinfo->attrdefs[j]->adef_expr);
/*
* Not Null constraint --- suppress if inherited
- *
- * Note: we could suppress this for serial columns since
- * SERIAL implies NOT NULL. We choose not to for forward
- * compatibility, since there has been some talk of making
- * SERIAL not imply NOT NULL, in which case the explicit
- * specification would be needed.
*/
if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
appendPQExpBuffer(q, " NOT NULL");
if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
return;
- /* Don't print inherited or serial defaults, either */
- if (tbinfo->inhAttrDef[adnum - 1] || tbinfo->attisserial[adnum - 1])
+ /* Don't print inherited defaults, either */
+ if (tbinfo->inhAttrDef[adnum - 1])
return;
q = createPQExpBuffer();
/*
* The logic we use for restoring sequences is as follows:
*
- * Add a basic CREATE SEQUENCE statement (use last_val for start if called
- * is false, else use min_val for start_val). Skip this if the sequence
- * came from a SERIAL column.
+ * Add a CREATE SEQUENCE statement as part of a "schema" dump
+ * (use last_val for start if called is false, else use min_val for
+ * start_val). Also, if the sequence is owned by a column, add an
+ * ALTER SEQUENCE SET OWNED command for it.
*
- * Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff we load
- * data. We do this for serial sequences too.
+ * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
*/
-
- if (!dataOnly && !OidIsValid(tbinfo->owning_tab))
+ if (!dataOnly)
{
resetPQExpBuffer(delqry);
false, "SEQUENCE", query->data, delqry->data, NULL,
tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
NULL, NULL);
+
+ /*
+ * If the sequence is owned by a table column, emit the ALTER for it
+ * as a separate TOC entry immediately following the sequence's own
+ * entry. It's OK to do this rather than using full sorting logic,
+ * because the dependency that tells us it's owned will have forced
+ * the table to be created first. We can't just include the ALTER
+ * in the TOC entry because it will fail if we haven't reassigned
+ * the sequence owner to match the table's owner.
+ *
+ * We need not schema-qualify the table reference because both
+ * sequence and table must be in the same schema.
+ */
+ if (OidIsValid(tbinfo->owning_tab))
+ {
+ TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
+
+ if (owning_tab)
+ {
+ resetPQExpBuffer(query);
+ appendPQExpBuffer(query, "ALTER SEQUENCE %s",
+ fmtId(tbinfo->dobj.name));
+ appendPQExpBuffer(query, " OWNED BY %s",
+ fmtId(owning_tab->dobj.name));
+ appendPQExpBuffer(query, ".%s;\n",
+ fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
+
+ ArchiveEntry(fout, nilCatalogId, createDumpId(),
+ tbinfo->dobj.name,
+ tbinfo->dobj.namespace->dobj.name,
+ NULL,
+ tbinfo->rolname,
+ false, "SEQUENCE OWNED BY", query->data, "", NULL,
+ &(tbinfo->dobj.dumpId), 1,
+ NULL, NULL);
+ }
+ }
+
+ /* Dump Sequence Comments */
+ resetPQExpBuffer(query);
+ appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
+ dumpComment(fout, query->data,
+ tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+ tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
}
if (!schemaOnly)
{
- TableInfo *owning_tab;
-
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
-
- /*
- * If this is a SERIAL sequence, then use the pg_get_serial_sequence
- * function to avoid hard-coding the sequence name. Note that this
- * implicitly assumes that the sequence and its owning table are in
- * the same schema, because we don't schema-qualify the reference.
- */
- if (OidIsValid(tbinfo->owning_tab) &&
- (owning_tab = findTableByOid(tbinfo->owning_tab)) != NULL)
- {
- appendPQExpBuffer(query, "pg_catalog.pg_get_serial_sequence(");
- appendStringLiteralAH(query, fmtId(owning_tab->dobj.name), fout);
- appendPQExpBuffer(query, ", ");
- appendStringLiteralAH(query, owning_tab->attnames[tbinfo->owning_col - 1], fout);
- appendPQExpBuffer(query, ")");
- }
- else
- appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
+ appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
appendPQExpBuffer(query, ", %s, %s);\n",
last, (called ? "true" : "false"));
NULL, NULL);
}
- if (!dataOnly)
- {
- /* Dump Sequence Comments */
- resetPQExpBuffer(query);
- appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
- dumpComment(fout, query->data,
- tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
- tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
- }
-
PQclear(res);
destroyPQExpBuffer(query);