提交 02eb8f4f 编写于 作者: B Bruce Momjian

Use schema search path to find the first matching contraint name for SET

CONSTRAINT, rather than affecting all constraints in all schemas (which
is what we used to do).  Also allow schema specifications.

Kris Jurka
上级 944a17bf
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/set_constraints.sgml,v 1.12 2004/09/10 18:39:53 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/ref/set_constraints.sgml,v 1.13 2006/04/27 00:33:32 momjian Exp $ -->
<refentry id="SQL-SET-CONSTRAINTS"> <refentry id="SQL-SET-CONSTRAINTS">
<refmeta> <refmeta>
<refentrytitle id="SQL-SET-CONSTRAINTS-title">SET CONSTRAINTS</refentrytitle> <refentrytitle id="SQL-SET-CONSTRAINTS-title">SET CONSTRAINTS</refentrytitle>
...@@ -45,10 +45,10 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ... ...@@ -45,10 +45,10 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ...
<para> <para>
<command>SET CONSTRAINTS</command> with a list of constraint names changes <command>SET CONSTRAINTS</command> with a list of constraint names changes
the mode of just those constraints (which must all be deferrable). If the mode of just those constraints (which must all be deferrable). The
there are multiple constraints matching any given name, all are affected. current schema search path is used to find the first matching name if
<command>SET CONSTRAINTS ALL</command> changes the mode of all deferrable no schema name is specified. <command>SET CONSTRAINTS ALL</command>
constraints. changes the mode of all deferrable constraints.
</para> </para>
<para> <para>
...@@ -93,13 +93,6 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ... ...@@ -93,13 +93,6 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ...
foreign-key constraints. foreign-key constraints.
</para> </para>
<para>
The SQL standard says that constraint names appearing in <command>SET
CONSTRAINTS</command> can be schema-qualified. This is not yet
supported by <productname>PostgreSQL</productname>: the names must
be unqualified, and all constraints matching the command will be
affected no matter which schema they are in.
</para>
</refsect1> </refsect1>
</refentry> </refentry>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.200 2006/03/05 15:58:25 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.201 2006/04/27 00:33:41 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_trigger.h" #include "catalog/pg_trigger.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "executor/executor.h" #include "executor/executor.h"
...@@ -37,6 +38,7 @@ ...@@ -37,6 +38,7 @@
#include "utils/inval.h" #include "utils/inval.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -2922,65 +2924,133 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt) ...@@ -2922,65 +2924,133 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
foreach(l, stmt->constraints) foreach(l, stmt->constraints)
{ {
char *cname = strVal(lfirst(l)); RangeVar *constraint = lfirst(l);
ScanKeyData skey; ScanKeyData skey;
SysScanDesc tgscan; SysScanDesc tgscan;
HeapTuple htup; HeapTuple htup;
bool found; bool found;
List *namespaceSearchList;
ListCell *namespaceSearchCell;
/* if (constraint->catalogname)
* Check that only named constraints are set explicitly {
*/ if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
if (strlen(cname) == 0) ereport(ERROR,
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
(errcode(ERRCODE_INVALID_NAME), errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
errmsg("unnamed constraints cannot be set explicitly"))); constraint->catalogname, constraint->schemaname,
constraint->relname)));
}
/* /*
* Setup to scan pg_trigger by tgconstrname ... * If we're given the schema name with the constraint, look only
* in that schema. If given a bare constraint name, use the
* search path to find the first matching constraint.
*/ */
ScanKeyInit(&skey, if (constraint->schemaname) {
Anum_pg_trigger_tgconstrname, Oid namespaceId = LookupExplicitNamespace(constraint->schemaname);
BTEqualStrategyNumber, F_NAMEEQ, namespaceSearchList = list_make1_oid(namespaceId);
PointerGetDatum(cname)); } else {
namespaceSearchList = fetch_search_path(true);
tgscan = systable_beginscan(tgrel, TriggerConstrNameIndexId, true, }
SnapshotNow, 1, &skey);
/*
* ... and search for the constraint trigger row
*/
found = false; found = false;
foreach(namespaceSearchCell, namespaceSearchList)
while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
{ {
Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup); Oid searchNamespaceId = lfirst_oid(namespaceSearchCell);
/*
* Setup to scan pg_trigger by tgconstrname ...
*/
ScanKeyInit(&skey,
Anum_pg_trigger_tgconstrname,
BTEqualStrategyNumber, F_NAMEEQ,
PointerGetDatum(constraint->relname));
tgscan = systable_beginscan(tgrel, TriggerConstrNameIndexId, true,
SnapshotNow, 1, &skey);
/* /*
* If we found some, check that they fit the deferrability but * ... and search for the constraint trigger row
* skip referential action ones, since they are silently never
* deferrable.
*/ */
if (pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD && while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL &&
pg_trigger->tgfoid != F_RI_FKEY_CASCADE_UPD &&
pg_trigger->tgfoid != F_RI_FKEY_CASCADE_DEL &&
pg_trigger->tgfoid != F_RI_FKEY_SETNULL_UPD &&
pg_trigger->tgfoid != F_RI_FKEY_SETNULL_DEL &&
pg_trigger->tgfoid != F_RI_FKEY_SETDEFAULT_UPD &&
pg_trigger->tgfoid != F_RI_FKEY_SETDEFAULT_DEL)
{ {
if (stmt->deferred && !pg_trigger->tgdeferrable) Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
ereport(ERROR, Relation constraintRel;
(errcode(ERRCODE_WRONG_OBJECT_TYPE), Oid constraintNamespaceId;
errmsg("constraint \"%s\" is not deferrable",
cname))); /*
oidlist = lappend_oid(oidlist, HeapTupleGetOid(htup)); * Foreign key constraints have triggers on both the
* parent and child tables. Since these tables may be
* in different schemas we must pick the child table
* because that table "owns" the constraint.
*
* Referential triggers on the parent table other than
* NOACTION_DEL and NOACTION_UPD are ignored below, so
* it is possible to not check them here, but it seems
* safer to always check.
*/
if (pg_trigger->tgfoid == F_RI_FKEY_NOACTION_DEL ||
pg_trigger->tgfoid == F_RI_FKEY_NOACTION_UPD ||
pg_trigger->tgfoid == F_RI_FKEY_RESTRICT_UPD ||
pg_trigger->tgfoid == F_RI_FKEY_RESTRICT_DEL ||
pg_trigger->tgfoid == F_RI_FKEY_CASCADE_UPD ||
pg_trigger->tgfoid == F_RI_FKEY_CASCADE_DEL ||
pg_trigger->tgfoid == F_RI_FKEY_SETNULL_UPD ||
pg_trigger->tgfoid == F_RI_FKEY_SETNULL_DEL ||
pg_trigger->tgfoid == F_RI_FKEY_SETDEFAULT_UPD ||
pg_trigger->tgfoid == F_RI_FKEY_SETDEFAULT_DEL)
{
constraintRel = RelationIdGetRelation(pg_trigger->tgconstrrelid);
} else {
constraintRel = RelationIdGetRelation(pg_trigger->tgrelid);
}
constraintNamespaceId = RelationGetNamespace(constraintRel);
RelationClose(constraintRel);
/*
* If this constraint is not in the schema we're
* currently searching for, keep looking.
*/
if (constraintNamespaceId != searchNamespaceId)
continue;
/*
* If we found some, check that they fit the deferrability but
* skip referential action ones, since they are silently never
* deferrable.
*/
if (pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_UPD &&
pg_trigger->tgfoid != F_RI_FKEY_RESTRICT_DEL &&
pg_trigger->tgfoid != F_RI_FKEY_CASCADE_UPD &&
pg_trigger->tgfoid != F_RI_FKEY_CASCADE_DEL &&
pg_trigger->tgfoid != F_RI_FKEY_SETNULL_UPD &&
pg_trigger->tgfoid != F_RI_FKEY_SETNULL_DEL &&
pg_trigger->tgfoid != F_RI_FKEY_SETDEFAULT_UPD &&
pg_trigger->tgfoid != F_RI_FKEY_SETDEFAULT_DEL)
{
if (stmt->deferred && !pg_trigger->tgdeferrable)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("constraint \"%s\" is not deferrable",
constraint->relname)));
oidlist = lappend_oid(oidlist, HeapTupleGetOid(htup));
}
found = true;
} }
found = true;
systable_endscan(tgscan);
/*
* Once we've found a matching constraint we do not search
* later parts of the search path.
*/
if (found)
break;
} }
systable_endscan(tgscan); list_free(namespaceSearchList);
/* /*
* Not found ? * Not found ?
...@@ -2989,7 +3059,7 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt) ...@@ -2989,7 +3059,7 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("constraint \"%s\" does not exist", errmsg("constraint \"%s\" does not exist",
cname))); constraint->relname)));
} }
heap_close(tgrel, AccessShareLock); heap_close(tgrel, AccessShareLock);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.542 2006/04/25 14:11:55 momjian Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.543 2006/04/27 00:33:45 momjian Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -1283,7 +1283,7 @@ ConstraintsSetStmt: ...@@ -1283,7 +1283,7 @@ ConstraintsSetStmt:
constraints_set_list: constraints_set_list:
ALL { $$ = NIL; } ALL { $$ = NIL; }
| name_list { $$ = $1; } | qualified_name_list { $$ = $1; }
; ;
constraints_set_mode: constraints_set_mode:
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.307 2006/04/15 17:45:41 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.308 2006/04/27 00:33:46 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1782,7 +1782,7 @@ typedef struct LockStmt ...@@ -1782,7 +1782,7 @@ typedef struct LockStmt
typedef struct ConstraintsSetStmt typedef struct ConstraintsSetStmt
{ {
NodeTag type; NodeTag type;
List *constraints; /* List of names as Value strings */ List *constraints; /* List of names as RangeVars */
bool deferred; bool deferred;
} ConstraintsSetStmt; } ConstraintsSetStmt;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册