diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-10-02 23:50:16 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-10-02 23:50:16 +0000 |
commit | aa731ed8433914641e42f32fec0fcf27f01aab7e (patch) | |
tree | 7120217579cb1a88552c7a1ee44cc0a0749d6e3e /src/backend | |
parent | 1b61ee3c69ccd869bddc56ae1021797a517ca9b7 (diff) | |
download | postgresql-aa731ed8433914641e42f32fec0fcf27f01aab7e.tar.gz postgresql-aa731ed8433914641e42f32fec0fcf27f01aab7e.zip |
Change nextval and other sequence functions to specify their sequence
argument as a 'regclass' value instead of a text string. The frontend
conversion of text string to pg_class OID is now encapsulated as an
implicitly-invocable coercion from text to regclass. This provides
backwards compatibility to the old behavior when the sequence argument
is explicitly typed as 'text'. When the argument is just an unadorned
literal string, it will be taken as 'regclass', which means that the
stored representation will be an OID. This solves longstanding problems
with renaming sequences that are referenced in default expressions, as
well as new-in-8.1 problems with renaming such sequences' schemas or
moving them to another schema. All per recent discussion.
Along the way, fix some rather serious problems in dbmirror's support
for mirroring sequence operations (int4 vs int8 confusion for instance).
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/dependency.c | 55 | ||||
-rw-r--r-- | src/backend/catalog/information_schema.sql | 5 | ||||
-rw-r--r-- | src/backend/commands/sequence.c | 102 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 63 | ||||
-rw-r--r-- | src/backend/parser/analyze.c | 7 | ||||
-rw-r--r-- | src/backend/utils/adt/regproc.c | 19 |
6 files changed, 140 insertions, 111 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 227b21c6564..8060055ff72 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.45 2005/07/07 20:39:57 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.46 2005/10/02 23:50:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1030,6 +1030,59 @@ find_expr_references_walker(Node *node, } return false; } + if (IsA(node, Const)) + { + Const *con = (Const *) node; + Oid objoid; + + /* + * If it's a regclass or similar literal referring to an existing + * object, add a reference to that object. (Currently, only the + * regclass case has any likely use, but we may as well handle all + * the OID-alias datatypes consistently.) + */ + if (!con->constisnull) + { + switch (con->consttype) + { + case REGPROCOID: + case REGPROCEDUREOID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists(PROCOID, + ObjectIdGetDatum(objoid), + 0, 0, 0)) + add_object_address(OCLASS_PROC, objoid, 0, + &context->addrs); + break; + case REGOPEROID: + case REGOPERATOROID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists(OPEROID, + ObjectIdGetDatum(objoid), + 0, 0, 0)) + add_object_address(OCLASS_OPERATOR, objoid, 0, + &context->addrs); + break; + case REGCLASSOID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists(RELOID, + ObjectIdGetDatum(objoid), + 0, 0, 0)) + add_object_address(OCLASS_CLASS, objoid, 0, + &context->addrs); + break; + case REGTYPEOID: + objoid = DatumGetObjectId(con->constvalue); + if (SearchSysCacheExists(TYPEOID, + ObjectIdGetDatum(objoid), + 0, 0, 0)) + add_object_address(OCLASS_TYPE, objoid, 0, + &context->addrs); + break; + } + } + return false; + } if (IsA(node, FuncExpr)) { FuncExpr *funcexpr = (FuncExpr *) node; diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index b56117a806f..4671f81f914 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -4,7 +4,7 @@ * * Copyright (c) 2003-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.30 2005/07/26 00:04:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.31 2005/10/02 23:50:07 tgl Exp $ */ /* @@ -357,7 +357,8 @@ CREATE VIEW columns AS CAST(a.attname AS sql_identifier) AS column_name, CAST(a.attnum AS cardinal_number) AS ordinal_position, CAST( - CASE WHEN pg_has_role(c.relowner, 'MEMBER') THEN ad.adsrc ELSE null END + CASE WHEN pg_has_role(c.relowner, 'MEMBER') THEN pg_get_expr(ad.adbin, ad.adrelid) + ELSE null END AS character_data) AS column_default, CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 5af9ba55b6e..9bf801f2308 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.123 2005/06/07 07:08:34 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.124 2005/10/02 23:50:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -75,12 +75,12 @@ static SeqTable seqtab = NULL; /* Head of list of SeqTable items */ */ static SeqTableData *last_used_seq = NULL; +static int64 nextval_internal(Oid relid); static void acquire_share_lock(Relation seqrel, SeqTable seq); -static void init_sequence(RangeVar *relation, - SeqTable *p_elm, Relation *p_rel); +static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel); static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf); static void init_params(List *options, Form_pg_sequence new, bool isInit); -static void do_setval(RangeVar *sequence, int64 next, bool iscalled); +static void do_setval(Oid relid, int64 next, bool iscalled); /* * DefineSequence @@ -302,6 +302,7 @@ DefineSequence(CreateSeqStmt *seq) void AlterSequence(AlterSeqStmt *stmt) { + Oid relid; SeqTable elm; Relation seqrel; Buffer buf; @@ -310,7 +311,8 @@ AlterSequence(AlterSeqStmt *stmt) FormData_pg_sequence new; /* open and AccessShareLock sequence */ - init_sequence(stmt->sequence, &elm, &seqrel); + relid = RangeVarGetRelid(stmt->sequence, false); + init_sequence(relid, &elm, &seqrel); /* allow ALTER to sequence owner only */ if (!pg_class_ownercheck(elm->relid, GetUserId())) @@ -372,11 +374,35 @@ AlterSequence(AlterSeqStmt *stmt) } +/* + * Note: nextval with a text argument is no longer exported as a pg_proc + * entry, but we keep it around to ease porting of C code that may have + * called the function directly. + */ Datum nextval(PG_FUNCTION_ARGS) { text *seqin = PG_GETARG_TEXT_P(0); RangeVar *sequence; + Oid relid; + + sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin)); + relid = RangeVarGetRelid(sequence, false); + + PG_RETURN_INT64(nextval_internal(relid)); +} + +Datum +nextval_oid(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + + PG_RETURN_INT64(nextval_internal(relid)); +} + +static int64 +nextval_internal(Oid relid) +{ SeqTable elm; Relation seqrel; Buffer buf; @@ -394,23 +420,21 @@ nextval(PG_FUNCTION_ARGS) rescnt = 0; bool logit = false; - sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin)); - /* open and AccessShareLock sequence */ - init_sequence(sequence, &elm, &seqrel); + init_sequence(relid, &elm, &seqrel); if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for sequence %s", - sequence->relname))); + RelationGetRelationName(seqrel)))); if (elm->last != elm->cached) /* some numbers were cached */ { last_used_seq = elm; elm->last += elm->increment; relation_close(seqrel, NoLock); - PG_RETURN_INT64(elm->last); + return elm->last; } /* lock page' buffer and read tuple */ @@ -481,7 +505,7 @@ nextval(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("nextval: reached maximum value of sequence \"%s\" (%s)", - sequence->relname, buf))); + RelationGetRelationName(seqrel), buf))); } next = minv; } @@ -504,7 +528,7 @@ nextval(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("nextval: reached minimum value of sequence \"%s\" (%s)", - sequence->relname, buf))); + RelationGetRelationName(seqrel), buf))); } next = maxv; } @@ -576,34 +600,31 @@ nextval(PG_FUNCTION_ARGS) relation_close(seqrel, NoLock); - PG_RETURN_INT64(result); + return result; } Datum -currval(PG_FUNCTION_ARGS) +currval_oid(PG_FUNCTION_ARGS) { - text *seqin = PG_GETARG_TEXT_P(0); - RangeVar *sequence; + Oid relid = PG_GETARG_OID(0); + int64 result; SeqTable elm; Relation seqrel; - int64 result; - - sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin)); /* open and AccessShareLock sequence */ - init_sequence(sequence, &elm, &seqrel); + init_sequence(relid, &elm, &seqrel); if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for sequence %s", - sequence->relname))); + RelationGetRelationName(seqrel)))); if (elm->increment == 0) /* nextval/read_info were not called */ ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("currval of sequence \"%s\" is not yet defined in this session", - sequence->relname))); + RelationGetRelationName(seqrel)))); result = elm->last; @@ -645,6 +666,7 @@ lastval(PG_FUNCTION_ARGS) result = last_used_seq->last; relation_close(seqrel, NoLock); + PG_RETURN_INT64(result); } @@ -662,7 +684,7 @@ lastval(PG_FUNCTION_ARGS) * sequence. */ static void -do_setval(RangeVar *sequence, int64 next, bool iscalled) +do_setval(Oid relid, int64 next, bool iscalled) { SeqTable elm; Relation seqrel; @@ -670,13 +692,13 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled) Form_pg_sequence seq; /* open and AccessShareLock sequence */ - init_sequence(sequence, &elm, &seqrel); + init_sequence(relid, &elm, &seqrel); if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for sequence %s", - sequence->relname))); + RelationGetRelationName(seqrel)))); /* lock page' buffer and read tuple */ seq = read_info(elm, seqrel, &buf); @@ -693,7 +715,8 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)", - bufv, sequence->relname, bufm, bufx))); + bufv, RelationGetRelationName(seqrel), + bufm, bufx))); } /* save info in local cache */ @@ -753,15 +776,12 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled) * See do_setval for discussion. */ Datum -setval(PG_FUNCTION_ARGS) +setval_oid(PG_FUNCTION_ARGS) { - text *seqin = PG_GETARG_TEXT_P(0); + Oid relid = PG_GETARG_OID(0); int64 next = PG_GETARG_INT64(1); - RangeVar *sequence; - sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin)); - - do_setval(sequence, next, true); + do_setval(relid, next, true); PG_RETURN_INT64(next); } @@ -771,16 +791,13 @@ setval(PG_FUNCTION_ARGS) * See do_setval for discussion. */ Datum -setval_and_iscalled(PG_FUNCTION_ARGS) +setval3_oid(PG_FUNCTION_ARGS) { - text *seqin = PG_GETARG_TEXT_P(0); + Oid relid = PG_GETARG_OID(0); int64 next = PG_GETARG_INT64(1); bool iscalled = PG_GETARG_BOOL(2); - RangeVar *sequence; - sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin)); - - do_setval(sequence, next, iscalled); + do_setval(relid, next, iscalled); PG_RETURN_INT64(next); } @@ -822,15 +839,14 @@ acquire_share_lock(Relation seqrel, SeqTable seq) } /* - * Given a relation name, open and lock the sequence. p_elm and p_rel are + * Given a relation OID, open and lock the sequence. p_elm and p_rel are * output parameters. */ static void -init_sequence(RangeVar *relation, SeqTable *p_elm, Relation *p_rel) +init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel) { - Oid relid = RangeVarGetRelid(relation, false); - volatile SeqTable elm; Relation seqrel; + volatile SeqTable elm; /* * Open the sequence relation. @@ -841,7 +857,7 @@ init_sequence(RangeVar *relation, SeqTable *p_elm, Relation *p_rel) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a sequence", - relation->relname))); + RelationGetRelationName(seqrel)))); /* Look to see if we already have a seqtable entry for relation */ for (elm = seqtab; elm != NULL; elm = elm->next) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index b3d0e017f15..b2877cebb76 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.171 2005/09/24 22:54:36 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.172 2005/10/02 23:50:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -168,8 +168,6 @@ static void AlterIndexNamespaces(Relation classRel, Relation rel, static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, const char *newNspName); -static void RebuildSerialDefaultExpr(Relation rel, AttrNumber attnum, - const char *seqname, const char *nspname); static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids); static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, @@ -6313,15 +6311,6 @@ AlterSeqNamespaces(Relation classRel, Relation rel, */ AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype, newNspOid, false); - /* - * And we need to rebuild the column default expression that - * relies on this sequence. - */ - if (depForm->refobjsubid > 0) - RebuildSerialDefaultExpr(rel, - depForm->refobjsubid, - RelationGetRelationName(seqRel), - newNspName); /* Now we can close it. Keep the lock till end of transaction. */ relation_close(seqRel, NoLock); @@ -6332,56 +6321,6 @@ AlterSeqNamespaces(Relation classRel, Relation rel, relation_close(depRel, AccessShareLock); } -/* - * Rebuild the default expression for a SERIAL column identified by rel - * and attnum. This is annoying, but we have to do it because the - * stored expression has the schema name as a text constant. - * - * The caller must be sure the specified column is really a SERIAL column, - * because no further checks are done here. - */ -static void -RebuildSerialDefaultExpr(Relation rel, AttrNumber attnum, - const char *seqname, const char *nspname) -{ - char *qstring; - A_Const *snamenode; - FuncCall *funccallnode; - RawColumnDefault *rawEnt; - - /* - * Create raw parse tree for the updated column default expression. - * This should match transformColumnDefinition() in parser/analyze.c. - */ - qstring = quote_qualified_identifier(nspname, seqname); - snamenode = makeNode(A_Const); - snamenode->val.type = T_String; - snamenode->val.val.str = qstring; - funccallnode = makeNode(FuncCall); - funccallnode->funcname = SystemFuncName("nextval"); - funccallnode->args = list_make1(snamenode); - funccallnode->agg_star = false; - funccallnode->agg_distinct = false; - - /* - * Remove any old default for the column. We use RESTRICT here for - * safety, but at present we do not expect anything to depend on the - * default. - */ - RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false); - - /* Do the equivalent of ALTER TABLE ... SET DEFAULT */ - rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault)); - rawEnt->attnum = attnum; - rawEnt->raw_default = (Node *) funccallnode; - - /* - * This function is intended for CREATE TABLE, so it processes a - * _list_ of defaults, but we just do one. - */ - AddRelationRawConstraints(rel, list_make1(rawEnt), NIL); -} - /* * This code supports diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 099bb714831..be91872df55 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.324 2005/08/01 20:31:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.325 2005/10/02 23:50:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -912,12 +912,15 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, * DEFAULT). * * Create an expression tree representing the function call - * nextval('"sequencename"') + * nextval('sequencename'). We cannot reduce the raw tree + * to cooked form until after the sequence is created, but + * there's no need to do so. */ qstring = quote_qualified_identifier(snamespace, sname); snamenode = makeNode(A_Const); snamenode->val.type = T_String; snamenode->val.val.str = qstring; + snamenode->typename = SystemTypeName("regclass"); funccallnode = makeNode(FuncCall); funccallnode->funcname = SystemFuncName("nextval"); funccallnode->args = list_make1(snamenode); diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 3f150010273..3a52c8756d1 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.94 2005/04/14 20:03:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.95 2005/10/02 23:50:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1090,6 +1090,23 @@ regtypesend(PG_FUNCTION_ARGS) /* + * text_regclass: convert text to regclass + */ +Datum +text_regclass(PG_FUNCTION_ARGS) +{ + text *relname = PG_GETARG_TEXT_P(0); + Oid result; + RangeVar *rv; + + rv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); + result = RangeVarGetRelid(rv, false); + + PG_RETURN_OID(result); +} + + +/* * Given a C string, parse it into a qualified-name list. */ List * |