77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.200 2006/03/05 15:58:25 momjian Exp $
10+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.201 2006/04/27 00:33:41 momjian Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
2424#include "catalog/pg_proc.h"
2525#include "catalog/pg_trigger.h"
2626#include "catalog/pg_type.h"
27+ #include "commands/dbcommands.h"
2728#include "commands/defrem.h"
2829#include "commands/trigger.h"
2930#include "executor/executor.h"
3738#include "utils/inval.h"
3839#include "utils/lsyscache.h"
3940#include "utils/memutils.h"
41+ #include "utils/relcache.h"
4042#include "utils/syscache.h"
4143
4244
@@ -2922,65 +2924,133 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
29222924
29232925 foreach (l , stmt -> constraints )
29242926 {
2925- char * cname = strVal ( lfirst (l ) );
2927+ RangeVar * constraint = lfirst (l );
29262928 ScanKeyData skey ;
29272929 SysScanDesc tgscan ;
29282930 HeapTuple htup ;
29292931 bool found ;
2932+ List * namespaceSearchList ;
2933+ ListCell * namespaceSearchCell ;
29302934
2931- /*
2932- * Check that only named constraints are set explicitly
2933- */
2934- if (strlen (cname ) == 0 )
2935- ereport (ERROR ,
2936- (errcode (ERRCODE_INVALID_NAME ),
2937- errmsg ("unnamed constraints cannot be set explicitly" )));
2935+ if (constraint -> catalogname )
2936+ {
2937+ if (strcmp (constraint -> catalogname , get_database_name (MyDatabaseId )) != 0 )
2938+ ereport (ERROR ,
2939+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
2940+ errmsg ("cross-database references are not implemented: \"%s.%s.%s\"" ,
2941+ constraint -> catalogname , constraint -> schemaname ,
2942+ constraint -> relname )));
2943+ }
29382944
2939- /*
2940- * Setup to scan pg_trigger by tgconstrname ...
2945+ /*
2946+ * If we're given the schema name with the constraint, look only
2947+ * in that schema. If given a bare constraint name, use the
2948+ * search path to find the first matching constraint.
29412949 */
2942- ScanKeyInit (& skey ,
2943- Anum_pg_trigger_tgconstrname ,
2944- BTEqualStrategyNumber , F_NAMEEQ ,
2945- PointerGetDatum (cname ));
2946-
2947- tgscan = systable_beginscan (tgrel , TriggerConstrNameIndexId , true,
2948- SnapshotNow , 1 , & skey );
2950+ if (constraint -> schemaname ) {
2951+ Oid namespaceId = LookupExplicitNamespace (constraint -> schemaname );
2952+ namespaceSearchList = list_make1_oid (namespaceId );
2953+ } else {
2954+ namespaceSearchList = fetch_search_path (true);
2955+ }
29492956
2950- /*
2951- * ... and search for the constraint trigger row
2952- */
29532957 found = false;
2954-
2955- while (HeapTupleIsValid (htup = systable_getnext (tgscan )))
2958+ foreach (namespaceSearchCell , namespaceSearchList )
29562959 {
2957- Form_pg_trigger pg_trigger = (Form_pg_trigger ) GETSTRUCT (htup );
2960+ Oid searchNamespaceId = lfirst_oid (namespaceSearchCell );
2961+
2962+ /*
2963+ * Setup to scan pg_trigger by tgconstrname ...
2964+ */
2965+ ScanKeyInit (& skey ,
2966+ Anum_pg_trigger_tgconstrname ,
2967+ BTEqualStrategyNumber , F_NAMEEQ ,
2968+ PointerGetDatum (constraint -> relname ));
2969+
2970+ tgscan = systable_beginscan (tgrel , TriggerConstrNameIndexId , true,
2971+ SnapshotNow , 1 , & skey );
29582972
29592973 /*
2960- * If we found some, check that they fit the deferrability but
2961- * skip referential action ones, since they are silently never
2962- * deferrable.
2974+ * ... and search for the constraint trigger row
29632975 */
2964- if (pg_trigger -> tgfoid != F_RI_FKEY_RESTRICT_UPD &&
2965- pg_trigger -> tgfoid != F_RI_FKEY_RESTRICT_DEL &&
2966- pg_trigger -> tgfoid != F_RI_FKEY_CASCADE_UPD &&
2967- pg_trigger -> tgfoid != F_RI_FKEY_CASCADE_DEL &&
2968- pg_trigger -> tgfoid != F_RI_FKEY_SETNULL_UPD &&
2969- pg_trigger -> tgfoid != F_RI_FKEY_SETNULL_DEL &&
2970- pg_trigger -> tgfoid != F_RI_FKEY_SETDEFAULT_UPD &&
2971- pg_trigger -> tgfoid != F_RI_FKEY_SETDEFAULT_DEL )
2976+ while (HeapTupleIsValid (htup = systable_getnext (tgscan )))
29722977 {
2973- if (stmt -> deferred && !pg_trigger -> tgdeferrable )
2974- ereport (ERROR ,
2975- (errcode (ERRCODE_WRONG_OBJECT_TYPE ),
2976- errmsg ("constraint \"%s\" is not deferrable" ,
2977- cname )));
2978- oidlist = lappend_oid (oidlist , HeapTupleGetOid (htup ));
2978+ Form_pg_trigger pg_trigger = (Form_pg_trigger ) GETSTRUCT (htup );
2979+ Relation constraintRel ;
2980+ Oid constraintNamespaceId ;
2981+
2982+ /*
2983+ * Foreign key constraints have triggers on both the
2984+ * parent and child tables. Since these tables may be
2985+ * in different schemas we must pick the child table
2986+ * because that table "owns" the constraint.
2987+ *
2988+ * Referential triggers on the parent table other than
2989+ * NOACTION_DEL and NOACTION_UPD are ignored below, so
2990+ * it is possible to not check them here, but it seems
2991+ * safer to always check.
2992+ */
2993+ if (pg_trigger -> tgfoid == F_RI_FKEY_NOACTION_DEL ||
2994+ pg_trigger -> tgfoid == F_RI_FKEY_NOACTION_UPD ||
2995+ pg_trigger -> tgfoid == F_RI_FKEY_RESTRICT_UPD ||
2996+ pg_trigger -> tgfoid == F_RI_FKEY_RESTRICT_DEL ||
2997+ pg_trigger -> tgfoid == F_RI_FKEY_CASCADE_UPD ||
2998+ pg_trigger -> tgfoid == F_RI_FKEY_CASCADE_DEL ||
2999+ pg_trigger -> tgfoid == F_RI_FKEY_SETNULL_UPD ||
3000+ pg_trigger -> tgfoid == F_RI_FKEY_SETNULL_DEL ||
3001+ pg_trigger -> tgfoid == F_RI_FKEY_SETDEFAULT_UPD ||
3002+ pg_trigger -> tgfoid == F_RI_FKEY_SETDEFAULT_DEL )
3003+ {
3004+ constraintRel = RelationIdGetRelation (pg_trigger -> tgconstrrelid );
3005+ } else {
3006+ constraintRel = RelationIdGetRelation (pg_trigger -> tgrelid );
3007+ }
3008+ constraintNamespaceId = RelationGetNamespace (constraintRel );
3009+ RelationClose (constraintRel );
3010+
3011+ /*
3012+ * If this constraint is not in the schema we're
3013+ * currently searching for, keep looking.
3014+ */
3015+ if (constraintNamespaceId != searchNamespaceId )
3016+ continue ;
3017+
3018+ /*
3019+ * If we found some, check that they fit the deferrability but
3020+ * skip referential action ones, since they are silently never
3021+ * deferrable.
3022+ */
3023+ if (pg_trigger -> tgfoid != F_RI_FKEY_RESTRICT_UPD &&
3024+ pg_trigger -> tgfoid != F_RI_FKEY_RESTRICT_DEL &&
3025+ pg_trigger -> tgfoid != F_RI_FKEY_CASCADE_UPD &&
3026+ pg_trigger -> tgfoid != F_RI_FKEY_CASCADE_DEL &&
3027+ pg_trigger -> tgfoid != F_RI_FKEY_SETNULL_UPD &&
3028+ pg_trigger -> tgfoid != F_RI_FKEY_SETNULL_DEL &&
3029+ pg_trigger -> tgfoid != F_RI_FKEY_SETDEFAULT_UPD &&
3030+ pg_trigger -> tgfoid != F_RI_FKEY_SETDEFAULT_DEL )
3031+ {
3032+ if (stmt -> deferred && !pg_trigger -> tgdeferrable )
3033+ ereport (ERROR ,
3034+ (errcode (ERRCODE_WRONG_OBJECT_TYPE ),
3035+ errmsg ("constraint \"%s\" is not deferrable" ,
3036+ constraint -> relname )));
3037+ oidlist = lappend_oid (oidlist , HeapTupleGetOid (htup ));
3038+ }
3039+ found = true;
29793040 }
2980- found = true;
3041+
3042+ systable_endscan (tgscan );
3043+
3044+ /*
3045+ * Once we've found a matching constraint we do not search
3046+ * later parts of the search path.
3047+ */
3048+ if (found )
3049+ break ;
3050+
29813051 }
29823052
2983- systable_endscan ( tgscan );
3053+ list_free ( namespaceSearchList );
29843054
29853055 /*
29863056 * Not found ?
@@ -2989,7 +3059,7 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
29893059 ereport (ERROR ,
29903060 (errcode (ERRCODE_UNDEFINED_OBJECT ),
29913061 errmsg ("constraint \"%s\" does not exist" ,
2992- cname )));
3062+ constraint -> relname )));
29933063 }
29943064 heap_close (tgrel , AccessShareLock );
29953065
0 commit comments