-<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.53 2006/02/11 22:17:18 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.54 2006/02/12 19:11:00 momjian Exp $ -->
<chapter id="ddl">
<title>Data Definition</title>
price numeric
);
</programlisting>
- Since <productname>PostgreSQL</productname> implements a UNIQUE constraint by
- means of an index, the above command will also create an index with the same
- name as the constraint. If you later on change the name of one of those, the
- name of the corresponding object will be changed automatically as well.
</para>
<indexterm>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_index.sgml,v 1.7 2006/02/11 22:17:18 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_index.sgml,v 1.8 2006/02/12 19:11:00 momjian Exp $
PostgreSQL documentation
-->
of <command>ALTER TABLE</> that apply to indexes.
</para>
- <para>
- Indexes are also used internally by constraints, namely by UNIQUE and
- PRIMARY KEY constraints. If you rename an index that is used internally by
- a constraint of that type, this constraint will implicitly be renamed as
- well. On the other hand, if you rename such a constraint, it will
- implicitly rename its corresponding index such that both objects always
- have the same name.
- </para>
-
<para>
There was formerly an <command>ALTER INDEX OWNER</> variant, but
this is now ignored (with a warning). An index cannot have an owner
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.83 2006/02/11 22:17:18 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.84 2006/02/12 19:11:00 momjian Exp $
PostgreSQL documentation
-->
<replaceable class="PARAMETER">action</replaceable> [, ... ]
ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [ * ]
RENAME [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> TO <replaceable class="PARAMETER">new_column</replaceable>
-ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [ * ]
- ALTER CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> RENAME TO <replaceable class="PARAMETER">new_constraint_name</replaceable>
ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
</listitem>
</varlistentry>
- <varlistentry>
- <term><literal>ALTER CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> RENAME TO <replaceable class="PARAMETER">new_constraint_name</replaceable></literal></term>
- <listitem>
- <para>
- This form renames a constraint that is defined on the table. Note that if
- a constraint is using an index internally (<literal>UNIQUE</> or
- <literal>PRIMARY KEY</> constraints), the corresponding index will be
- renamed as well.
- </para>
- </listitem>
- </varlistentry>
-
<varlistentry>
<term><literal>ADD <replaceable class="PARAMETER">table_constraint</replaceable></literal></term>
<listitem>
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.29 2006/02/11 22:17:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.30 2006/02/12 19:11:01 momjian Exp $
*
*-------------------------------------------------------------------------
*/
heap_close(conRel, RowExclusiveLock);
}
-
-
-/*
- * RenameConstraint
- * Rename a single constraint record
- * conId: The OID of the constraint to rename
- * newName: The new name of the constraint
- * implicitRename: is this an implicit rename? If so, we will issue
- * a notice about the implicit rename
- * cmdName: the command that triggered the rename for the "implicitly
- * renames" notice message
- */
-void
-RenameConstraint(Oid conId, const char* newName,
- bool implicitRename, const char* cmdName)
-{
- Relation conRel;
- ScanKeyData key[1];
- SysScanDesc scan;
- HeapTuple tup;
- NameData newNameData;
- Relation rel;
- Oid relId;
- Oid nspOid;
- Form_pg_constraint conform;
-
- /* before reading the tuple, lock the table it constraints in
- * AccessExclusiveLock mode. Otherwise, if we read it before locking this
- * table, the tuple might be changed by another transaction and our copy
- * would be out of date
- */
- relId = GetConstraintRelationId(conId);
- if (!OidIsValid(relId))
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("constraint with OID %d does not exist", conId)));
- }
-
- rel = relation_open(relId, AccessExclusiveLock);
- nspOid = get_rel_namespace(relId);
-
- conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
-
- ScanKeyInit(&key[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(conId));
-
- scan = systable_beginscan(conRel, ConstraintOidIndexId, true,
- SnapshotNow, 1, key);
- if (!HeapTupleIsValid((tup = systable_getnext(scan))))
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("constraint with OID %d does not exist", conId)));
- }
-
- conform = (Form_pg_constraint) GETSTRUCT(tup);
-
- if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
- conform->conrelid,
- get_rel_namespace(conform->conrelid),
- newName))
- {
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("constraint \"%s\" for relation \"%s\" already exists",
- newName,
- RelationGetRelationName(rel))));
- }
- tup = heap_copytuple(tup);
- conform = (Form_pg_constraint) GETSTRUCT(tup);
-
- if (implicitRename && cmdName)
- {
- ereport(NOTICE,
- (errmsg("%s will implicitly rename constraint "
- "\"%s\" to \"%s\" on table \"%s.%s\"",
- cmdName,
- NameStr(conform->conname),
- newName,
- get_namespace_name(nspOid),
- RelationGetRelationName(rel))));
- }
-
- namestrcpy(&newNameData, newName);
- conform->conname = newNameData;
-
- simple_heap_update(conRel, &tup->t_self, tup);
- CatalogUpdateIndexes(conRel, tup);
- heap_freetuple(tup);
-
- systable_endscan(scan);
- heap_close(conRel, RowExclusiveLock);
-
- /* close relation but hold lock until end of transaction */
- relation_close(rel, NoLock);
-}
-
-
-/* GetRelationConstraintOid
- *
- * Get the contraint OID by the relation Id of the relation it constraints and
- * this relations' name. We need this function in order to rename a constraint.
- * This is done via "ALTER TABLE ... ALTER CONSTRAINT name" and the parser
- * gives us the relation this constraint is defined on as well as the
- * constraint's name.
- *
- * The function returns:
- *
- * - the unique OID of the constraint if the constraint could be found
- * - the invalid OID if the constraint was not found
- *
- */
-Oid GetRelationConstraintOid(Oid relId, const char* name)
-{
- Relation conRel;
- ScanKeyData key[1];
- SysScanDesc scan;
- HeapTuple tup;
- Oid conId = InvalidOid;
-
- /* we don't change data, so an AccessShareLock is enough */
- conRel = heap_open(ConstraintRelationId, AccessShareLock);
-
- ScanKeyInit(&key[0],
- Anum_pg_constraint_conrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(relId));
-
- scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
- SnapshotNow, 1, key);
-
- while (HeapTupleIsValid((tup = systable_getnext(scan))))
- {
- Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
- if (pg_strcasecmp(name, NameStr(con->conname)) == 0)
- {
- conId = HeapTupleGetOid(tup);
- Assert(OidIsValid(conId));
- }
- }
-
- systable_endscan(scan);
- heap_close(conRel, AccessShareLock);
-
- return conId;
-}
-
-
-/* GetConstraintRelationId
- *
- * Gets the OID of the relation where the constraint is defined on or the
- * invalid OID if the constraint cannot be found.
- */
-Oid GetConstraintRelationId(Oid conId)
-{
- Relation conRel;
- ScanKeyData key[1];
- SysScanDesc scan;
- HeapTuple tup;
- Oid relId = InvalidOid;
-
- /* we don't change data, so an AccessShareLock is enough */
- conRel = heap_open(ConstraintRelationId, AccessShareLock);
-
- ScanKeyInit(&key[0],
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(conId));
-
- scan = systable_beginscan(conRel, ConstraintOidIndexId, true,
- SnapshotNow, 1, key);
-
- if (HeapTupleIsValid((tup = systable_getnext(scan))))
- {
- Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
- relId = con->conrelid;
- Assert(OidIsValid(relId));
- }
-
- systable_endscan(scan);
- heap_close(conRel, AccessShareLock);
-
- return relId;
-}
-
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.18 2006/02/11 22:17:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.19 2006/02/12 19:11:01 momjian Exp $
*
*-------------------------------------------------------------------------
*/
return ret;
}
-
-List* getReferencingOids(Oid refClassId, Oid refObjId, Oid refObjSubId,
- Oid classId, DependencyType deptype)
-{
- ScanKeyData key[3];
- SysScanDesc scan;
- HeapTuple tup;
- Relation depRel;
- List *list = NIL;
-
- depRel = heap_open(DependRelationId, AccessShareLock);
-
- ScanKeyInit(&key[0],
- Anum_pg_depend_refclassid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(refClassId));
-
- ScanKeyInit(&key[1],
- Anum_pg_depend_refobjid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(refObjId));
-
- ScanKeyInit(&key[2],
- Anum_pg_depend_refobjsubid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(refObjSubId));
-
- scan = systable_beginscan(depRel, DependReferenceIndexId, true,
- SnapshotNow, 3, key);
-
- while (HeapTupleIsValid(tup = systable_getnext(scan)))
- {
- Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
-
- /* check if the class id is what we want */
- if (depForm->classid != classId)
- continue;
-
- /* check if the DependencyType is what we want */
- if (depForm->deptype != deptype)
- continue;
-
- /* if we are still here, we have found a match */
- list = lcons_oid(depForm->objid, list);
- break;
- }
- systable_endscan(scan);
-
- heap_close(depRel, AccessShareLock);
- return list;
-}
-
-
-List* getDependentOids(Oid classId, Oid objId,
- Oid refClassId, DependencyType deptype)
-{
- ScanKeyData key[2];
- SysScanDesc scan;
- HeapTuple tup;
- Relation depRel;
- List *list = NIL;
-
- depRel = heap_open(DependRelationId, AccessShareLock);
-
- ScanKeyInit(&key[0],
- Anum_pg_depend_classid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(classId));
-
- ScanKeyInit(&key[1],
- Anum_pg_depend_objid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(objId));
-
- scan = systable_beginscan(depRel, DependDependerIndexId, true,
- SnapshotNow, 2, key);
-
- while (HeapTupleIsValid(tup = systable_getnext(scan)))
- {
- Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
-
- /* check if the DependencyType is what we want */
- if (depForm->deptype != deptype)
- continue;
-
- /* check if the referenced class id is what we want */
- if (depForm->refclassid != refClassId)
- continue;
-
- /* if we are still here, we have found a match */
- list = lcons_oid(depForm->refobjid, list);
- break;
- }
- systable_endscan(scan);
-
- heap_close(depRel, AccessShareLock);
- return list;
-}
-
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.16 2006/02/11 22:17:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.17 2006/02/12 19:11:01 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/htup.h"
#include "catalog/catalog.h"
-#include "catalog/dependency.h"
#include "catalog/namespace.h"
#include "catalog/pg_class.h"
-#include "catalog/pg_constraint.h"
#include "commands/alter.h"
#include "commands/conversioncmds.h"
#include "commands/dbcommands.h"
case OBJECT_INDEX:
case OBJECT_COLUMN:
case OBJECT_TRIGGER:
- case OBJECT_CONSTRAINT:
{
Oid relid;
AclResult aclresult;
aclresult = pg_namespace_aclcheck(namespaceId,
- GetUserId(), ACL_CREATE);
+ GetUserId(),
+ ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceId));
- /*
- * Do NOT refer to stmt->renameType here because
- * you can also rename an index with ALTER TABLE
- */
- if (get_rel_relkind(relid) == RELKIND_INDEX)
- {
- /* see if we depend on a constraint */
- List* depOids = getDependentOids(
- RelationRelationId, relid,
- ConstraintRelationId,
- DEPENDENCY_INTERNAL);
-
- /* there should only be one constraint */
- Assert(list_length(depOids) <= 1);
- if (list_length(depOids) == 1)
- {
- Oid conRelId = linitial_oid(depOids);
- /*
- * Apply the same name to the
- * constraint and tell it that this
- * is an implicit rename triggered
- * by an "ALTER INDEX" command.
- */
- RenameConstraint(conRelId,
- stmt->newname, true, "ALTER INDEX");
- }
- }
renamerel(relid, stmt->newname);
break;
}
stmt->subname, /* old att name */
stmt->newname); /* new att name */
break;
- case OBJECT_CONSTRAINT:
- /* XXX could do extra function renameconstr() - but I
- * don't know where it should go */
- /* renameconstr(relid,
- stmt->subname,
- stmt->newname); */
- {
- List *depRelOids;
- ListCell *l;
- Oid conId =
- GetRelationConstraintOid(relid,
- stmt->subname);
- if (!OidIsValid(conId)) {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("constraint with name \"%s\" "
- "does not exist",
- stmt->subname)));
- }
- RenameConstraint(conId, stmt->newname,
- false, NULL);
- depRelOids = getReferencingOids(
- ConstraintRelationId, conId, 0,
- RelationRelationId,
- DEPENDENCY_INTERNAL);
- foreach(l, depRelOids)
- {
- Oid depRelOid;
- Oid nspOid;
- depRelOid = lfirst_oid(l);
- nspOid = get_rel_namespace(depRelOid);
- if (get_rel_relkind(depRelOid) == RELKIND_INDEX)
- {
- ereport(NOTICE,
- (errmsg("ALTER TABLE / CONSTRAINT will implicitly rename index "
- "\"%s\" to \"%s\" on table \"%s.%s\"",
- get_rel_name(depRelOid),
- stmt->newname,
- get_namespace_name(nspOid),
- get_rel_name(relid))));
- renamerel(depRelOid, stmt->newname);
- }
- }
- }
- break;
-
default:
/* can't happen */ ;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.528 2006/02/12 03:22:17 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.529 2006/02/12 19:11:01 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
n->newname = $8;
$$ = (Node *)n;
}
- | ALTER TABLE relation_expr ALTER CONSTRAINT name RENAME TO name
- {
- RenameStmt *n = makeNode(RenameStmt);
- n->renameType = OBJECT_CONSTRAINT;
- n->relation = $3;
- n->subname = $6;
- n->newname = $9;
- $$ = (Node *)n;
- }
| ALTER TRIGGER name ON relation_expr RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.251 2006/02/11 22:17:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.252 2006/02/12 19:11:01 momjian Exp $
*
*-------------------------------------------------------------------------
*/
case OBJECT_SCHEMA:
tag = "ALTER SCHEMA";
break;
- case OBJECT_CONSTRAINT:
case OBJECT_COLUMN:
case OBJECT_TABLE:
tag = "ALTER TABLE";
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.19 2006/02/11 22:17:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.20 2006/02/12 19:11:01 momjian Exp $
*
*-------------------------------------------------------------------------
*/
extern bool objectIsInternalDependency(Oid classId, Oid objectId);
-extern List* getDependentOids(Oid classId, Oid objId,
- Oid refClassId, DependencyType deptype);
-
-extern List* getReferencingOids(Oid refClassId, Oid refObjId, Oid refObjSubId,
- Oid classId, DependencyType deptype);
-
/* in pg_shdepend.c */
extern void recordSharedDependencyOn(ObjectAddress *depender,
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.20 2006/02/11 22:17:19 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.21 2006/02/12 19:11:01 momjian Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
Oid newNspId, bool isType);
-extern void RenameConstraint(Oid conId, const char* newName,
- bool implicitRename, const char* cmdName);
-
-extern Oid GetRelationConstraintOid(Oid relId, const char* name);
-extern Oid GetConstraintRelationId(Oid conId);
-
#endif /* PG_CONSTRAINT_H */
CREATE TABLE tmp4 (a int, b int, unique(a,b));
NOTICE: CREATE TABLE / UNIQUE will create implicit index "tmp4_a_key" for table "tmp4"
CREATE TABLE tmp5 (a int, b int);
--- creates implicit index tmp6_a_key
-CREATE TABLE tmp6 (a int, b int, unique(a));
-NOTICE: CREATE TABLE / UNIQUE will create implicit index "tmp6_a_key" for table "tmp6"
-CREATE INDEX tmp6_b_key ON tmp6(b);
-- Insert rows into tmp2 (pktable)
INSERT INTO tmp2 values (1);
INSERT INTO tmp2 values (2);
-- tmp4 is a,b
ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full;
ERROR: there is no unique constraint matching given keys for referenced table "tmp4"
--- check if constraint and index name stay in sync if we rename one or the other
--- fail here
-ALTER TABLE tmp6 ALTER CONSTRAINT tmp6_a_key RENAME TO tmp6_b_key;
-NOTICE: ALTER TABLE / CONSTRAINT will implicitly rename index "tmp6_a_key" to "tmp6_b_key" on table "public.tmp6"
-ERROR: relation "tmp6_b_key" already exists
--- succeed
-ALTER TABLE tmp6 ALTER CONSTRAINT tmp6_a_key RENAME TO tmp6_c_key;
-NOTICE: ALTER TABLE / CONSTRAINT will implicitly rename index "tmp6_a_key" to "tmp6_c_key" on table "public.tmp6"
--- Now rename the index (this fails)
-ALTER INDEX tmp6_c_key RENAME TO tmp6_b_key;
-NOTICE: ALTER INDEX will implicitly rename constraint "tmp6_c_key" to "tmp6_b_key" on table "public.tmp6"
-ERROR: relation "tmp6_b_key" already exists
--- this succeeds and uses ALTER TABLE syntax to rename an INDEX
-ALTER TABLE tmp6_c_key RENAME TO tmp6_a_key;
-NOTICE: ALTER INDEX will implicitly rename constraint "tmp6_c_key" to "tmp6_a_key" on table "public.tmp6"
-DROP TABLE tmp6;
DROP TABLE tmp5;
DROP TABLE tmp4;
DROP TABLE tmp3;
CREATE TABLE tmp5 (a int, b int);
--- creates implicit index tmp6_a_key
-CREATE TABLE tmp6 (a int, b int, unique(a));
-CREATE INDEX tmp6_b_key ON tmp6(b);
-
-- Insert rows into tmp2 (pktable)
INSERT INTO tmp2 values (1);
INSERT INTO tmp2 values (2);
ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full;
--- check if constraint and index name stay in sync if we rename one or the other
--- fail here
-ALTER TABLE tmp6 ALTER CONSTRAINT tmp6_a_key RENAME TO tmp6_b_key;
-
--- succeed
-ALTER TABLE tmp6 ALTER CONSTRAINT tmp6_a_key RENAME TO tmp6_c_key;
-
--- Now rename the index (this fails)
-ALTER INDEX tmp6_c_key RENAME TO tmp6_b_key;
-
--- this succeeds and uses ALTER TABLE syntax to rename an INDEX
-ALTER TABLE tmp6_c_key RENAME TO tmp6_a_key;
-
-DROP TABLE tmp6;
-
DROP TABLE tmp5;
DROP TABLE tmp4;