From a0e842d81b435681a46e6dd1e50f14f9967ced37 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 25 Jun 2004 17:20:29 +0000 Subject: [PATCH] Add pg_get_serial_sequence() function, and cause pg_dump to use it. This eliminates the assumption that a serial column's sequence will have the same name on reload that it was given in the original database. Christopher Kings-Lynne --- doc/src/sgml/func.sgml | 65 +++++++++++------ src/backend/utils/adt/ruleutils.c | 114 +++++++++++++++++++++++++++++- src/bin/pg_dump/pg_dump.c | 22 +++++- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_proc.h | 4 +- src/include/utils/builtins.h | 5 +- 6 files changed, 185 insertions(+), 29 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 106c4cf775..3c23f43a59 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,5 +1,5 @@ @@ -7228,29 +7228,13 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); pg_get_userbyid + + pg_get_serial_sequence + + lists functions that extract information from the system catalogs. - pg_get_viewdef, - pg_get_ruledef, - pg_get_indexdef, - pg_get_triggerdef, and - pg_get_constraintdef respectively - reconstruct the creating command for a view, rule, index, trigger, or - constraint. (Note that this is a decompiled reconstruction, not - the original text of the command.) Most of these come in two - variants, one of which can optionally pretty-print the result. - The pretty-printed format is more readable, but the default format is more - likely to be - interpreted the same way by future versions of PostgreSQL; - avoid using pretty-printed output for dump purposes. - Passing false for the pretty-print parameter yields the - same result as the variant that does not have the parameter at all. - pg_get_expr decompiles the internal form of an - individual expression, such as the default value for a column. It - may be useful when examining the contents of system catalogs. - pg_get_userbyid - extracts a user's name given a user ID number. @@ -7335,10 +7319,49 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); nameget user name with given ID + + pg_get_serial_sequence(table_name, column_name) + text + get name of the sequence that a serial or bigserial column + uses +
+ + pg_get_viewdef, + pg_get_ruledef, + pg_get_indexdef, + pg_get_triggerdef, and + pg_get_constraintdef respectively + reconstruct the creating command for a view, rule, index, trigger, or + constraint. (Note that this is a decompiled reconstruction, not + the original text of the command.) + pg_get_expr decompiles the internal form of an + individual expression, such as the default value for a column. It + may be useful when examining the contents of system catalogs. + Most of these functions come in two + variants, one of which can optionally pretty-print the result. + The pretty-printed format is more readable, but the default format is more + likely to be + interpreted the same way by future versions of PostgreSQL; + avoid using pretty-printed output for dump purposes. + Passing false for the pretty-print parameter yields the + same result as the variant that does not have the parameter at all. + + + + pg_get_userbyid + extracts a user's name given a user ID number. + pg_get_serial_sequence + fetches the name of the sequence associated with a serial or + bigserial column. The name is suitably formatted + for passing to the sequence functions (see ). + NULL is returned if the column does not have a sequence attached. + + obj_description diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 1a2fe54d7a..208cbf5d31 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * back to source text * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.173 2004/06/18 06:13:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.174 2004/06/25 17:20:24 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -42,12 +42,14 @@ #include "access/genam.h" #include "catalog/catname.h" +#include "catalog/dependency.h" #include "catalog/heap.h" #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_cast.h" #include "catalog/pg_constraint.h" +#include "catalog/pg_depend.h" #include "catalog/pg_index.h" #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" @@ -1232,6 +1234,116 @@ pg_get_userbyid(PG_FUNCTION_ARGS) PG_RETURN_NAME(result); } + +/* + * pg_get_serial_sequence + * Get the name of the sequence used by a serial column, + * formatted suitably for passing to setval, nextval or currval. + */ +Datum +pg_get_serial_sequence(PG_FUNCTION_ARGS) +{ + text *tablename = PG_GETARG_TEXT_P(0); + text *columnname = PG_GETARG_TEXT_P(1); + RangeVar *tablerv; + Oid tableOid; + char *column; + AttrNumber attnum; + Oid sequenceId = InvalidOid; + Relation depRel; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple tup; + + /* Get the OID of the table */ + tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename, + "pg_get_serial_sequence")); + tableOid = RangeVarGetRelid(tablerv, false); + + /* Get the number of the column */ + column = DatumGetCString(DirectFunctionCall1(textout, + PointerGetDatum(columnname))); + + attnum = get_attnum(tableOid, column); + if (attnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + column, tablerv->relname))); + + /* Search the dependency table for the dependent sequence */ + depRel = heap_openr(DependRelationName, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelOid_pg_class)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(tableOid)); + ScanKeyInit(&key[2], + Anum_pg_depend_refobjsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(attnum)); + + scan = systable_beginscan(depRel, DependReferenceIndex, true, + SnapshotNow, 3, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); + + /* + * We assume any internal dependency of a relation on a column + * must be what we are looking for. + */ + if (deprec->classid == RelOid_pg_class && + deprec->objsubid == 0 && + deprec->deptype == DEPENDENCY_INTERNAL) + { + sequenceId = deprec->objid; + break; + } + } + + systable_endscan(scan); + heap_close(depRel, AccessShareLock); + + if (OidIsValid(sequenceId)) + { + HeapTuple classtup; + Form_pg_class classtuple; + char *nspname; + char *result; + + /* Get the sequence's pg_class entry */ + classtup = SearchSysCache(RELOID, + ObjectIdGetDatum(sequenceId), + 0, 0, 0); + if (!HeapTupleIsValid(classtup)) + elog(ERROR, "cache lookup failed for relation %u", sequenceId); + classtuple = (Form_pg_class) GETSTRUCT(classtup); + + /* Get the namespace */ + nspname = get_namespace_name(classtuple->relnamespace); + if (!nspname) + elog(ERROR, "cache lookup failed for namespace %u", + classtuple->relnamespace); + + /* And construct the result string */ + result = quote_qualified_identifier(nspname, + NameStr(classtuple->relname)); + + ReleaseSysCache(classtup); + + PG_RETURN_TEXT_P(string_to_text(result)); + } + + PG_RETURN_NULL(); +} + + /* ---------- * deparse_expression - General utility for deparsing expressions * diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 694a42e3b4..00793ebbce 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.376 2004/06/21 13:36:41 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.377 2004/06/25 17:20:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -7319,9 +7319,27 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) if (!schemaOnly) { + TableInfo *owning_tab; + resetPQExpBuffer(query); appendPQExpBuffer(query, "SELECT pg_catalog.setval("); - appendStringLiteral(query, fmtId(tbinfo->dobj.name), true); + /* + * 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("); + appendStringLiteral(query, fmtId(owning_tab->dobj.name), true); + appendPQExpBuffer(query, ", "); + appendStringLiteral(query, owning_tab->attnames[tbinfo->owning_col-1], true); + appendPQExpBuffer(query, ")"); + } + else + appendStringLiteral(query, fmtId(tbinfo->dobj.name), true); appendPQExpBuffer(query, ", %s, %s);\n", last, (called ? "true" : "false")); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 8bb47ad78c..ac6f8a1fa0 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.239 2004/06/21 04:06:07 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.240 2004/06/25 17:20:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200406202 +#define CATALOG_VERSION_NO 200406251 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index ecaf82efab..489fa9ca9b 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.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/include/catalog/pg_proc.h,v 1.338 2004/06/16 01:26:49 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.339 2004/06/25 17:20:28 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2238,6 +2238,8 @@ DATA(insert OID = 1387 ( pg_get_constraintdef PGNSP PGUID 12 f f t f s 1 25 "26 DESCR("constraint description"); DATA(insert OID = 1716 ( pg_get_expr PGNSP PGUID 12 f f t f s 2 25 "25 26" _null_ pg_get_expr - _null_ )); DESCR("deparse an encoded expression"); +DATA(insert OID = 1665 ( pg_get_serial_sequence PGNSP PGUID 12 f f t f s 2 25 "25 25" _null_ pg_get_serial_sequence - _null_ )); +DESCR("name of sequence for a serial column"); /* Generic referential integrity constraint triggers */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 281f3067fa..99974cdec1 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.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/include/utils/builtins.h,v 1.243 2004/06/13 21:57:26 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.244 2004/06/25 17:20:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -472,9 +472,10 @@ extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS); extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS); extern Datum pg_get_constraintdef_ext(PG_FUNCTION_ARGS); extern char *pg_get_constraintdef_string(Oid constraintId); -extern Datum pg_get_userbyid(PG_FUNCTION_ARGS); extern Datum pg_get_expr(PG_FUNCTION_ARGS); extern Datum pg_get_expr_ext(PG_FUNCTION_ARGS); +extern Datum pg_get_userbyid(PG_FUNCTION_ARGS); +extern Datum pg_get_serial_sequence(PG_FUNCTION_ARGS); extern char *deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit); extern List *deparse_context_for(const char *aliasname, Oid relid); -- 2.40.0