diff --git a/doc/src/sgml/ref/set_constraints.sgml b/doc/src/sgml/ref/set_constraints.sgml
index 3bcde91f386914e4013a2c42096599b06518f5d0..9af82008aa32b279adf9b08b0116fb50d3ca4cc3 100644
--- a/doc/src/sgml/ref/set_constraints.sgml
+++ b/doc/src/sgml/ref/set_constraints.sgml
@@ -1,4 +1,4 @@
-<!-- $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">
  <refmeta>
   <refentrytitle id="SQL-SET-CONSTRAINTS-title">SET CONSTRAINTS</refentrytitle>
@@ -45,10 +45,10 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ...
 
   <para>
    <command>SET CONSTRAINTS</command> with a list of constraint names changes
-   the mode of just those constraints (which must all be deferrable).  If
-   there are multiple constraints matching any given name, all are affected.
-   <command>SET CONSTRAINTS ALL</command> changes the mode of all deferrable
-   constraints.
+   the mode of just those constraints (which must all be deferrable).  The
+   current schema search path is used to find the first matching name if
+   no schema name is specified.  <command>SET CONSTRAINTS ALL</command> 
+   changes the mode of all deferrable constraints.
   </para>
 
   <para>
@@ -93,13 +93,6 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ...
    foreign-key constraints.
   </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>
 </refentry>
 
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 336aa67fdd52898fcdc5cb8b4962c021fc89ecc5..256b2ca411d5cd0b441eca1872be5412b6c7e637 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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 @@
 #include "catalog/pg_proc.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
+#include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/trigger.h"
 #include "executor/executor.h"
@@ -37,6 +38,7 @@
 #include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/relcache.h"
 #include "utils/syscache.h"
 
 
@@ -2922,65 +2924,133 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
 
 		foreach(l, stmt->constraints)
 		{
-			char	   *cname = strVal(lfirst(l));
+			RangeVar   *constraint = lfirst(l);
 			ScanKeyData skey;
 			SysScanDesc tgscan;
 			HeapTuple	htup;
 			bool		found;
+			List	   *namespaceSearchList;
+			ListCell   *namespaceSearchCell;
 
-			/*
-			 * Check that only named constraints are set explicitly
-			 */
-			if (strlen(cname) == 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_NAME),
-					errmsg("unnamed constraints cannot be set explicitly")));
+			if (constraint->catalogname)
+			{
+				if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
+									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,
-						Anum_pg_trigger_tgconstrname,
-						BTEqualStrategyNumber, F_NAMEEQ,
-						PointerGetDatum(cname));
-
-			tgscan = systable_beginscan(tgrel, TriggerConstrNameIndexId, true,
-										SnapshotNow, 1, &skey);
+			if (constraint->schemaname) {
+				Oid namespaceId = LookupExplicitNamespace(constraint->schemaname);
+				namespaceSearchList = list_make1_oid(namespaceId);
+			} else {
+				namespaceSearchList = fetch_search_path(true);
+			}
 
-			/*
-			 * ... and search for the constraint trigger row
-			 */
 			found = false;
-
-			while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
+			foreach(namespaceSearchCell, namespaceSearchList)
 			{
-				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
-				 * skip referential action ones, since they are silently never
-				 * deferrable.
+				 * ... and search for the constraint trigger row
 				 */
-				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)
+				while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
 				{
-					if (stmt->deferred && !pg_trigger->tgdeferrable)
-						ereport(ERROR,
-								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-								 errmsg("constraint \"%s\" is not deferrable",
-										cname)));
-					oidlist = lappend_oid(oidlist, HeapTupleGetOid(htup));
+					Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
+					Relation constraintRel;
+					Oid constraintNamespaceId;
+
+					/*
+					 * 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 ?
@@ -2989,7 +3059,7 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
 				ereport(ERROR,
 						(errcode(ERRCODE_UNDEFINED_OBJECT),
 						 errmsg("constraint \"%s\" does not exist",
-								cname)));
+								constraint->relname)));
 		}
 		heap_close(tgrel, AccessShareLock);
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 46aff33bc2242a9ff7e27dd96ab05b0554c5baa0..8870261e44134192c24eee648c3ef067160b67b0 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * 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
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -1283,7 +1283,7 @@ ConstraintsSetStmt:
 
 constraints_set_list:
 			ALL										{ $$ = NIL; }
-			| name_list								{ $$ = $1; }
+			| qualified_name_list					{ $$ = $1; }
 		;
 
 constraints_set_mode:
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index e4eb385df87c983a7d94162dadc1e18c1b3e19e7..2da0f6605dd2d3e76ff7fa2a45d9c2b557853dd8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * 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
 typedef struct ConstraintsSetStmt
 {
 	NodeTag		type;
-	List	   *constraints;	/* List of names as Value strings */
+	List	   *constraints;	/* List of names as RangeVars */
 	bool		deferred;
 } ConstraintsSetStmt;