aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/sequence.c133
-rw-r--r--src/backend/commands/tablecmds.c100
-rw-r--r--src/backend/commands/view.c3
3 files changed, 177 insertions, 59 deletions
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 6154a4ed3da..865c2f60fe5 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.138 2006/07/31 20:09:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.139 2006/08/21 00:57:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,6 +17,7 @@
#include "access/heapam.h"
#include "access/transam.h"
#include "access/xact.h"
+#include "catalog/dependency.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
@@ -26,6 +27,7 @@
#include "nodes/makefuncs.h"
#include "utils/acl.h"
#include "utils/builtins.h"
+#include "utils/lsyscache.h"
#include "utils/resowner.h"
#include "utils/syscache.h"
@@ -82,8 +84,11 @@ static int64 nextval_internal(Oid relid);
static Relation open_share_lock(SeqTable seq);
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 init_params(List *options, bool isInit,
+ Form_pg_sequence new, List **owned_by);
static void do_setval(Oid relid, int64 next, bool iscalled);
+static void process_owned_by(Relation seqrel, List *owned_by);
+
/*
* DefineSequence
@@ -93,6 +98,7 @@ void
DefineSequence(CreateSeqStmt *seq)
{
FormData_pg_sequence new;
+ List *owned_by;
CreateStmt *stmt = makeNode(CreateStmt);
Oid seqoid;
Relation rel;
@@ -107,7 +113,7 @@ DefineSequence(CreateSeqStmt *seq)
NameData name;
/* Check and set all option values */
- init_params(seq->options, &new, true);
+ init_params(seq->options, true, &new, &owned_by);
/*
* Create relation (and fill *null & *value)
@@ -123,7 +129,6 @@ DefineSequence(CreateSeqStmt *seq)
coldef->raw_default = NULL;
coldef->cooked_default = NULL;
coldef->constraints = NIL;
- coldef->support = NULL;
null[i - 1] = ' ';
@@ -287,6 +292,10 @@ DefineSequence(CreateSeqStmt *seq)
UnlockReleaseBuffer(buf);
+ /* process OWNED BY if given */
+ if (owned_by)
+ process_owned_by(rel, owned_by);
+
heap_close(rel, NoLock);
}
@@ -305,6 +314,7 @@ AlterSequence(AlterSeqStmt *stmt)
Page page;
Form_pg_sequence seq;
FormData_pg_sequence new;
+ List *owned_by;
/* open and AccessShareLock sequence */
relid = RangeVarGetRelid(stmt->sequence, false);
@@ -323,7 +333,7 @@ AlterSequence(AlterSeqStmt *stmt)
memcpy(&new, seq, sizeof(FormData_pg_sequence));
/* Check and set new values */
- init_params(stmt->options, &new, false);
+ init_params(stmt->options, false, &new, &owned_by);
/* Now okay to update the on-disk tuple */
memcpy(seq, &new, sizeof(FormData_pg_sequence));
@@ -366,6 +376,10 @@ AlterSequence(AlterSeqStmt *stmt)
UnlockReleaseBuffer(buf);
+ /* process OWNED BY if given */
+ if (owned_by)
+ process_owned_by(seqrel, owned_by);
+
relation_close(seqrel, NoLock);
}
@@ -933,13 +947,15 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
/*
* init_params: process the options list of CREATE or ALTER SEQUENCE,
- * and store the values into appropriate fields of *new.
+ * and store the values into appropriate fields of *new. Also set
+ * *owned_by to any OWNED BY option, or to NIL if there is none.
*
* If isInit is true, fill any unspecified options with default values;
* otherwise, do not change existing options that aren't explicitly overridden.
*/
static void
-init_params(List *options, Form_pg_sequence new, bool isInit)
+init_params(List *options, bool isInit,
+ Form_pg_sequence new, List **owned_by)
{
DefElem *last_value = NULL;
DefElem *increment_by = NULL;
@@ -949,6 +965,8 @@ init_params(List *options, Form_pg_sequence new, bool isInit)
DefElem *is_cycled = NULL;
ListCell *option;
+ *owned_by = NIL;
+
foreach(option, options)
{
DefElem *defel = (DefElem *) lfirst(option);
@@ -1006,6 +1024,14 @@ init_params(List *options, Form_pg_sequence new, bool isInit)
errmsg("conflicting or redundant options")));
is_cycled = defel;
}
+ else if (strcmp(defel->defname, "owned_by") == 0)
+ {
+ if (*owned_by)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ *owned_by = defGetQualifiedName(defel);
+ }
else
elog(ERROR, "option \"%s\" not recognized",
defel->defname);
@@ -1130,6 +1156,99 @@ init_params(List *options, Form_pg_sequence new, bool isInit)
new->cache_value = 1;
}
+/*
+ * Process an OWNED BY option for CREATE/ALTER SEQUENCE
+ *
+ * Ownership permissions on the sequence are already checked,
+ * but if we are establishing a new owned-by dependency, we must
+ * enforce that the referenced table has the same owner and namespace
+ * as the sequence.
+ */
+static void
+process_owned_by(Relation seqrel, List *owned_by)
+{
+ int nnames;
+ Relation tablerel;
+ AttrNumber attnum;
+
+ nnames = list_length(owned_by);
+ Assert(nnames > 0);
+ if (nnames == 1)
+ {
+ /* Must be OWNED BY NONE */
+ if (strcmp(strVal(linitial(owned_by)), "none") != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("invalid OWNED BY option"),
+ errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
+ tablerel = NULL;
+ attnum = 0;
+ }
+ else
+ {
+ List *relname;
+ char *attrname;
+ RangeVar *rel;
+
+ /* Separate relname and attr name */
+ relname = list_truncate(list_copy(owned_by), nnames - 1);
+ attrname = strVal(lfirst(list_tail(owned_by)));
+
+ /* Open and lock rel to ensure it won't go away meanwhile */
+ rel = makeRangeVarFromNameList(relname);
+ tablerel = relation_openrv(rel, AccessShareLock);
+
+ /* Must be a regular table */
+ if (tablerel->rd_rel->relkind != RELKIND_RELATION)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("referenced relation \"%s\" is not a table",
+ RelationGetRelationName(tablerel))));
+
+ /* We insist on same owner and schema */
+ if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("sequence must have same owner as table it is owned by")));
+ if (RelationGetNamespace(seqrel) != RelationGetNamespace(tablerel))
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("sequence must be in same schema as table it is owned by")));
+
+ /* Now, fetch the attribute number from the system cache */
+ attnum = get_attnum(RelationGetRelid(tablerel), attrname);
+ if (attnum == InvalidAttrNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ attrname, RelationGetRelationName(tablerel))));
+ }
+
+ /*
+ * OK, we are ready to update pg_depend. First remove any existing
+ * AUTO dependencies for the sequence, then optionally add a new one.
+ */
+ markSequenceUnowned(RelationGetRelid(seqrel));
+
+ if (tablerel)
+ {
+ ObjectAddress refobject,
+ depobject;
+
+ refobject.classId = RelationRelationId;
+ refobject.objectId = RelationGetRelid(tablerel);
+ refobject.objectSubId = attnum;
+ depobject.classId = RelationRelationId;
+ depobject.objectId = RelationGetRelid(seqrel);
+ depobject.objectSubId = 0;
+ recordDependencyOn(&depobject, &refobject, DEPENDENCY_AUTO);
+ }
+
+ /* Done, but hold lock until commit */
+ if (tablerel)
+ relation_close(tablerel, NoLock);
+}
+
void
seq_redo(XLogRecPtr lsn, XLogRecord *record)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cd4c4eb2304..a1f76033377 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.199 2006/08/03 20:57:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.200 2006/08/21 00:57:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -209,8 +209,6 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
ColumnDef *colDef);
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
-static void add_column_support_dependency(Oid relid, int32 attnum,
- RangeVar *support);
static void ATExecDropNotNull(Relation rel, const char *colName);
static void ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
const char *colName);
@@ -476,10 +474,6 @@ DefineRelation(CreateStmt *stmt, char relkind)
* work unless we have a pre-existing relation. So, the transformation has
* to be postponed to this final step of CREATE TABLE.
*
- * Another task that's conveniently done at this step is to add dependency
- * links between columns and supporting relations (such as SERIAL
- * sequences).
- *
* First, scan schema to find new column defaults.
*/
rawDefaults = NIL;
@@ -502,10 +496,6 @@ DefineRelation(CreateStmt *stmt, char relkind)
rawEnt->raw_default = colDef->raw_default;
rawDefaults = lappend(rawDefaults, rawEnt);
}
-
- /* Create dependency for supporting relation for this column */
- if (colDef->support != NULL)
- add_column_support_dependency(relationId, attnum, colDef->support);
}
/*
@@ -944,7 +934,6 @@ MergeAttributes(List *schema, List *supers, bool istemp,
def->raw_default = NULL;
def->cooked_default = NULL;
def->constraints = NIL;
- def->support = NULL;
inhSchema = lappend(inhSchema, def);
newattno[parent_attno - 1] = ++child_attno;
}
@@ -1159,9 +1148,10 @@ varattnos_map(TupleDesc old, TupleDesc new)
return attmap;
}
-/* Generate a map for change_varattnos_of_a_node from a tupledesc and a list of
- * ColumnDefs */
-
+/*
+ * Generate a map for change_varattnos_of_a_node from a tupledesc and a list of
+ * ColumnDefs
+ */
AttrNumber *
varattnos_map_schema(TupleDesc old, List *schema)
{
@@ -3017,8 +3007,6 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
/* Child should see column as singly inherited */
colDefChild->inhcount = 1;
colDefChild->is_local = false;
- /* and don't make a support dependency on the child */
- colDefChild->support = NULL;
ATOneLevelRecursion(wqueue, rel, childCmd);
}
@@ -3259,8 +3247,6 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
* Add needed dependency entries for the new column.
*/
add_column_datatype_dependency(myrelid, i, attribute->atttypid);
- if (colDef->support != NULL)
- add_column_support_dependency(myrelid, i, colDef->support);
}
/*
@@ -3282,24 +3268,6 @@ add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
}
/*
- * Install a dependency for a column's supporting relation (serial sequence).
- */
-static void
-add_column_support_dependency(Oid relid, int32 attnum, RangeVar *support)
-{
- ObjectAddress colobject,
- suppobject;
-
- colobject.classId = RelationRelationId;
- colobject.objectId = relid;
- colobject.objectSubId = attnum;
- suppobject.classId = RelationRelationId;
- suppobject.objectId = RangeVarGetRelid(support, false);
- suppobject.objectSubId = 0;
- recordDependencyOn(&suppobject, &colobject, DEPENDENCY_INTERNAL);
-}
-
-/*
* ALTER TABLE ALTER COLUMN DROP NOT NULL
*/
static void
@@ -5444,9 +5412,9 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
/*
* ALTER TABLE OWNER
*
- * recursing is true if we are recursing from a table to its indexes or
- * toast table. We don't allow the ownership of those things to be
- * changed separately from the parent table. Also, we can skip permission
+ * recursing is true if we are recursing from a table to its indexes,
+ * sequences, or toast table. We don't allow the ownership of those things to
+ * be changed separately from the parent table. Also, we can skip permission
* checks (this is necessary not just an optimization, else we'd fail to
* handle toast tables properly).
*/
@@ -5479,7 +5447,6 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
{
case RELKIND_RELATION:
case RELKIND_VIEW:
- case RELKIND_SEQUENCE:
/* ok to change owner */
break;
case RELKIND_INDEX:
@@ -5502,6 +5469,24 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing)
newOwnerId = tuple_class->relowner;
}
break;
+ case RELKIND_SEQUENCE:
+ if (!recursing &&
+ tuple_class->relowner != newOwnerId)
+ {
+ /* if it's an owned sequence, disallow changing it by itself */
+ Oid tableId;
+ int32 colId;
+
+ if (sequenceIsOwned(relationOid, &tableId, &colId))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot change owner of sequence \"%s\"",
+ NameStr(tuple_class->relname)),
+ errdetail("Sequence \"%s\" is linked to table \"%s\".",
+ NameStr(tuple_class->relname),
+ get_rel_name(tableId))));
+ }
+ break;
case RELKIND_TOASTVALUE:
if (recursing)
break;
@@ -5644,7 +5629,7 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId)
HeapTuple tup;
/*
- * SERIAL sequences are those having an internal dependency on one of the
+ * SERIAL sequences are those having an auto dependency on one of the
* table's columns (we don't care *which* column, exactly).
*/
depRel = heap_open(DependRelationId, AccessShareLock);
@@ -5667,11 +5652,11 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId)
Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
Relation seqRel;
- /* skip dependencies other than internal dependencies on columns */
+ /* skip dependencies other than auto dependencies on columns */
if (depForm->refobjsubid == 0 ||
depForm->classid != RelationRelationId ||
depForm->objsubid != 0 ||
- depForm->deptype != DEPENDENCY_INTERNAL)
+ depForm->deptype != DEPENDENCY_AUTO)
continue;
/* Use relation_open just in case it's an index */
@@ -5686,7 +5671,7 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId)
}
/* We don't need to close the sequence while we alter it. */
- ATExecChangeOwner(depForm->objid, newOwnerId, false);
+ ATExecChangeOwner(depForm->objid, newOwnerId, true);
/* Now we can close it. Keep the lock till end of transaction. */
relation_close(seqRel, NoLock);
@@ -6549,6 +6534,9 @@ AlterTableNamespace(RangeVar *relation, const char *newschema)
rel = heap_openrv(relation, AccessExclusiveLock);
+ relid = RelationGetRelid(rel);
+ oldNspOid = RelationGetNamespace(rel);
+
/* heap_openrv allows TOAST, but we don't want to */
if (rel->rd_rel->relkind == RELKIND_TOASTVALUE)
ereport(ERROR,
@@ -6556,8 +6544,20 @@ AlterTableNamespace(RangeVar *relation, const char *newschema)
errmsg("\"%s\" is a TOAST relation",
RelationGetRelationName(rel))));
- relid = RelationGetRelid(rel);
- oldNspOid = RelationGetNamespace(rel);
+ /* if it's an owned sequence, disallow moving it by itself */
+ if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
+ {
+ Oid tableId;
+ int32 colId;
+
+ if (sequenceIsOwned(relid, &tableId, &colId))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot move an owned sequence into another schema"),
+ errdetail("Sequence \"%s\" is linked to table \"%s\".",
+ RelationGetRelationName(rel),
+ get_rel_name(tableId))));
+ }
/* get schema OID and check its permissions */
nspOid = LookupCreationNamespace(newschema);
@@ -6699,7 +6699,7 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
HeapTuple tup;
/*
- * SERIAL sequences are those having an internal dependency on one of the
+ * SERIAL sequences are those having an auto dependency on one of the
* table's columns (we don't care *which* column, exactly).
*/
depRel = heap_open(DependRelationId, AccessShareLock);
@@ -6722,11 +6722,11 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
Relation seqRel;
- /* skip dependencies other than internal dependencies on columns */
+ /* skip dependencies other than auto dependencies on columns */
if (depForm->refobjsubid == 0 ||
depForm->classid != RelationRelationId ||
depForm->objsubid != 0 ||
- depForm->deptype != DEPENDENCY_INTERNAL)
+ depForm->deptype != DEPENDENCY_AUTO)
continue;
/* Use relation_open just in case it's an index */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 63850cbeae7..df7f479f316 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.96 2006/07/13 16:49:14 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.97 2006/08/21 00:57:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -126,7 +126,6 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
def->raw_default = NULL;
def->cooked_default = NULL;
def->constraints = NIL;
- def->support = NULL;
attrList = lappend(attrList, def);
}