aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r--src/backend/commands/tablecmds.c563
1 files changed, 130 insertions, 433 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 001bc571548..cea8ddeabf9 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.213 2007/02/02 00:07:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.214 2007/02/14 01:58:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,7 @@
#include "catalog/pg_depend.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
+#include "catalog/pg_opclass.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/toasting.h"
@@ -139,6 +140,7 @@ typedef struct NewConstraint
char *name; /* Constraint name, or NULL if none */
ConstrType contype; /* CHECK or FOREIGN */
Oid refrelid; /* PK rel, if FOREIGN */
+ Oid conid; /* OID of pg_constraint entry, if FOREIGN */
Node *qual; /* Check expr or FkConstraint struct */
List *qualstate; /* Execution state for CHECK */
} NewConstraint;
@@ -186,10 +188,9 @@ static Oid transformFkeyCheckAttrs(Relation pkrel,
int numattrs, int16 *attnums,
Oid *opclasses);
static void validateForeignKeyConstraint(FkConstraint *fkconstraint,
- Relation rel, Relation pkrel);
+ Relation rel, Relation pkrel, Oid constraintOid);
static void createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
- Oid constrOid);
-static char *fkMatchTypeToString(char match_type);
+ Oid constraintOid);
static void ATController(Relation rel, List *cmds, bool recurse);
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
bool recurse, bool recursing);
@@ -256,11 +257,6 @@ static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
static void ATExecAddInherit(Relation rel, RangeVar *parent);
static void ATExecDropInherit(Relation rel, RangeVar *parent);
static void copy_relation_data(Relation rel, SMgrRelation dst);
-static void update_ri_trigger_args(Oid relid,
- const char *oldname,
- const char *newname,
- bool fk_scan,
- bool update_relname);
/* ----------------------------------------------------------------
@@ -1615,21 +1611,6 @@ renameatt(Oid myrelid,
heap_close(attrelation, RowExclusiveLock);
- /*
- * Update att name in any RI triggers associated with the relation.
- */
- if (targetrelation->rd_rel->reltriggers > 0)
- {
- /* update tgargs column reference where att is primary key */
- update_ri_trigger_args(RelationGetRelid(targetrelation),
- oldattname, newattname,
- false, false);
- /* update tgargs column reference where att is foreign key */
- update_ri_trigger_args(RelationGetRelid(targetrelation),
- oldattname, newattname,
- true, false);
- }
-
relation_close(targetrelation, NoLock); /* close rel but keep lock */
}
@@ -1709,226 +1690,12 @@ renamerel(Oid myrelid, const char *newrelname)
TypeRename(oldrelname, namespaceId, newrelname);
/*
- * Update rel name in any RI triggers associated with the relation.
- */
- if (relhastriggers)
- {
- /* update tgargs where relname is primary key */
- update_ri_trigger_args(myrelid,
- oldrelname,
- newrelname,
- false, true);
- /* update tgargs where relname is foreign key */
- update_ri_trigger_args(myrelid,
- oldrelname,
- newrelname,
- true, true);
- }
-
- /*
* Close rel, but keep exclusive lock!
*/
relation_close(targetrelation, NoLock);
}
/*
- * Scan pg_trigger for RI triggers that are on the specified relation
- * (if fk_scan is false) or have it as the tgconstrrel (if fk_scan
- * is true). Update RI trigger args fields matching oldname to contain
- * newname instead. If update_relname is true, examine the relname
- * fields; otherwise examine the attname fields.
- */
-static void
-update_ri_trigger_args(Oid relid,
- const char *oldname,
- const char *newname,
- bool fk_scan,
- bool update_relname)
-{
- Relation tgrel;
- ScanKeyData skey[1];
- SysScanDesc trigscan;
- HeapTuple tuple;
- Datum values[Natts_pg_trigger];
- char nulls[Natts_pg_trigger];
- char replaces[Natts_pg_trigger];
-
- tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
- if (fk_scan)
- {
- ScanKeyInit(&skey[0],
- Anum_pg_trigger_tgconstrrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(relid));
- trigscan = systable_beginscan(tgrel, TriggerConstrRelidIndexId,
- true, SnapshotNow,
- 1, skey);
- }
- else
- {
- ScanKeyInit(&skey[0],
- Anum_pg_trigger_tgrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(relid));
- trigscan = systable_beginscan(tgrel, TriggerRelidNameIndexId,
- true, SnapshotNow,
- 1, skey);
- }
-
- while ((tuple = systable_getnext(trigscan)) != NULL)
- {
- Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
- bytea *val;
- bytea *newtgargs;
- bool isnull;
- int tg_type;
- bool examine_pk;
- bool changed;
- int tgnargs;
- int i;
- int newlen;
- const char *arga[RI_MAX_ARGUMENTS];
- const char *argp;
-
- tg_type = RI_FKey_trigger_type(pg_trigger->tgfoid);
- if (tg_type == RI_TRIGGER_NONE)
- {
- /* Not an RI trigger, forget it */
- continue;
- }
-
- /*
- * It is an RI trigger, so parse the tgargs bytea.
- *
- * NB: we assume the field will never be compressed or moved out of
- * line; so does trigger.c ...
- */
- tgnargs = pg_trigger->tgnargs;
- val = DatumGetByteaP(fastgetattr(tuple,
- Anum_pg_trigger_tgargs,
- tgrel->rd_att, &isnull));
- if (isnull || tgnargs < RI_FIRST_ATTNAME_ARGNO ||
- tgnargs > RI_MAX_ARGUMENTS)
- {
- /* This probably shouldn't happen, but ignore busted triggers */
- continue;
- }
- argp = (const char *) VARDATA(val);
- for (i = 0; i < tgnargs; i++)
- {
- arga[i] = argp;
- argp += strlen(argp) + 1;
- }
-
- /*
- * Figure out which item(s) to look at. If the trigger is primary-key
- * type and attached to my rel, I should look at the PK fields; if it
- * is foreign-key type and attached to my rel, I should look at the FK
- * fields. But the opposite rule holds when examining triggers found
- * by tgconstrrel search.
- */
- examine_pk = (tg_type == RI_TRIGGER_PK) == (!fk_scan);
-
- changed = false;
- if (update_relname)
- {
- /* Change the relname if needed */
- i = examine_pk ? RI_PK_RELNAME_ARGNO : RI_FK_RELNAME_ARGNO;
- if (strcmp(arga[i], oldname) == 0)
- {
- arga[i] = newname;
- changed = true;
- }
- }
- else
- {
- /* Change attname(s) if needed */
- i = examine_pk ? RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_PK_IDX :
- RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_FK_IDX;
- for (; i < tgnargs; i += 2)
- {
- if (strcmp(arga[i], oldname) == 0)
- {
- arga[i] = newname;
- changed = true;
- }
- }
- }
-
- if (!changed)
- {
- /* Don't need to update this tuple */
- continue;
- }
-
- /*
- * Construct modified tgargs bytea.
- */
- newlen = VARHDRSZ;
- for (i = 0; i < tgnargs; i++)
- newlen += strlen(arga[i]) + 1;
- newtgargs = (bytea *) palloc(newlen);
- VARATT_SIZEP(newtgargs) = newlen;
- newlen = VARHDRSZ;
- for (i = 0; i < tgnargs; i++)
- {
- strcpy(((char *) newtgargs) + newlen, arga[i]);
- newlen += strlen(arga[i]) + 1;
- }
-
- /*
- * Build modified tuple.
- */
- for (i = 0; i < Natts_pg_trigger; i++)
- {
- values[i] = (Datum) 0;
- replaces[i] = ' ';
- nulls[i] = ' ';
- }
- values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(newtgargs);
- replaces[Anum_pg_trigger_tgargs - 1] = 'r';
-
- tuple = heap_modifytuple(tuple, RelationGetDescr(tgrel), values, nulls, replaces);
-
- /*
- * Update pg_trigger and its indexes
- */
- simple_heap_update(tgrel, &tuple->t_self, tuple);
-
- CatalogUpdateIndexes(tgrel, tuple);
-
- /*
- * Invalidate trigger's relation's relcache entry so that other
- * backends (and this one too!) are sent SI message to make them
- * rebuild relcache entries. (Ideally this should happen
- * automatically...)
- *
- * We can skip this for triggers on relid itself, since that relcache
- * flush will happen anyway due to the table or column rename. We
- * just need to catch the far ends of RI relationships.
- */
- pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
- if (pg_trigger->tgrelid != relid)
- CacheInvalidateRelcacheByRelid(pg_trigger->tgrelid);
-
- /* free up our scratch memory */
- pfree(newtgargs);
- heap_freetuple(tuple);
- }
-
- systable_endscan(trigscan);
-
- heap_close(tgrel, RowExclusiveLock);
-
- /*
- * Increment cmd counter to make updates visible; this is needed in case
- * the same tuple has to be updated again by next pass (can happen in case
- * of a self-referential FK relationship).
- */
- CommandCounterIncrement();
-}
-
-/*
* AlterTable
* Execute ALTER TABLE, which can be a list of subcommands
*
@@ -2552,7 +2319,8 @@ ATRewriteTables(List **wqueue)
refrel = heap_open(con->refrelid, RowShareLock);
- validateForeignKeyConstraint(fkconstraint, rel, refrel);
+ validateForeignKeyConstraint(fkconstraint, rel, refrel,
+ con->conid);
heap_close(refrel, NoLock);
}
@@ -4061,6 +3829,9 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
Oid pktypoid[INDEX_MAX_KEYS];
Oid fktypoid[INDEX_MAX_KEYS];
Oid opclasses[INDEX_MAX_KEYS];
+ Oid pfeqoperators[INDEX_MAX_KEYS];
+ Oid ppeqoperators[INDEX_MAX_KEYS];
+ Oid ffeqoperators[INDEX_MAX_KEYS];
int i;
int numfks,
numpks;
@@ -4138,6 +3909,9 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
MemSet(pktypoid, 0, sizeof(pktypoid));
MemSet(fktypoid, 0, sizeof(fktypoid));
MemSet(opclasses, 0, sizeof(opclasses));
+ MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
+ MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
+ MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
numfks = transformColumnNameList(RelationGetRelid(rel),
fkconstraint->fk_attrs,
@@ -4166,7 +3940,15 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
opclasses);
}
- /* Be sure referencing and referenced column types are comparable */
+ /*
+ * Look up the equality operators to use in the constraint.
+ *
+ * Note that we look for operator(s) with the PK type on the left; when
+ * the types are different this is the right choice because the PK index
+ * will need operators with the indexkey on the left. Also, we take the
+ * PK type as being the declared input type of the opclass, which might be
+ * binary-compatible but not identical to the PK column type.
+ */
if (numfks != numpks)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FOREIGN_KEY),
@@ -4174,24 +3956,71 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
for (i = 0; i < numpks; i++)
{
+ HeapTuple cla_ht;
+ Form_pg_opclass cla_tup;
+ Oid amid;
+ Oid opfamily;
+ Oid pktype;
+ Oid fktype;
+ Oid pfeqop;
+ Oid ppeqop;
+ Oid ffeqop;
+ int16 eqstrategy;
+
+ /* We need several fields out of the pg_opclass entry */
+ cla_ht = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(opclasses[i]),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(cla_ht))
+ elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
+ cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
+ amid = cla_tup->opcmethod;
+ opfamily = cla_tup->opcfamily;
+ pktype = cla_tup->opcintype;
+ ReleaseSysCache(cla_ht);
+
/*
- * pktypoid[i] is the primary key table's i'th key's type fktypoid[i]
- * is the foreign key table's i'th key's type
- *
- * Note that we look for an operator with the PK type on the left;
- * when the types are different this is critical because the PK index
- * will need operators with the indexkey on the left. (Ordinarily both
- * commutator operators will exist if either does, but we won't get
- * the right answer from the test below on opclass membership unless
- * we select the proper operator.)
+ * Check it's a btree; currently this can never fail since no other
+ * index AMs support unique indexes. If we ever did have other
+ * types of unique indexes, we'd need a way to determine which
+ * operator strategy number is equality. (Is it reasonable to
+ * insist that every such index AM use btree's number for equality?)
+ */
+ if (amid != BTREE_AM_OID)
+ elog(ERROR, "only b-tree indexes are supported for foreign keys");
+ eqstrategy = BTEqualStrategyNumber;
+
+ /*
+ * There had better be a PK = PK operator for the index.
+ */
+ ppeqop = get_opfamily_member(opfamily, pktype, pktype, eqstrategy);
+
+ if (!OidIsValid(ppeqop))
+ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
+ eqstrategy, pktype, pktype, opfamily);
+
+ /*
+ * Are there equality operators that take exactly the FK type?
+ * Assume we should look through any domain here.
*/
- Operator o = oper(NULL, list_make1(makeString("=")),
- pktypoid[i], fktypoid[i],
- true, -1);
+ fktype = getBaseType(fktypoid[i]);
+
+ pfeqop = get_opfamily_member(opfamily, pktype, fktype, eqstrategy);
+ ffeqop = get_opfamily_member(opfamily, fktype, fktype, eqstrategy);
- if (o == NULL)
+ if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
+ {
+ /*
+ * Otherwise, look for an implicit cast from the FK type to
+ * the PK type, and if found, use the PK type's equality operator.
+ */
+ if (can_coerce_type(1, &fktype, &pktype, COERCION_IMPLICIT))
+ pfeqop = ffeqop = ppeqop;
+ }
+
+ if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("foreign key constraint \"%s\" "
"cannot be implemented",
fkconstraint->constr_name),
@@ -4202,41 +4031,9 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
format_type_be(fktypoid[i]),
format_type_be(pktypoid[i]))));
- /*
- * Check that the found operator is compatible with the PK index, and
- * generate a warning if not, since otherwise costly seqscans will be
- * incurred to check FK validity.
- */
- if (!op_in_opfamily(oprid(o), get_opclass_family(opclasses[i])))
- ereport(WARNING,
- (errmsg("foreign key constraint \"%s\" "
- "will require costly sequential scans",
- fkconstraint->constr_name),
- errdetail("Key columns \"%s\" and \"%s\" "
- "are of different types: %s and %s.",
- strVal(list_nth(fkconstraint->fk_attrs, i)),
- strVal(list_nth(fkconstraint->pk_attrs, i)),
- format_type_be(fktypoid[i]),
- format_type_be(pktypoid[i]))));
-
- ReleaseSysCache(o);
- }
-
- /*
- * Tell Phase 3 to check that the constraint is satisfied by existing rows
- * (we can skip this during table creation).
- */
- if (!fkconstraint->skip_validation)
- {
- NewConstraint *newcon;
-
- newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
- newcon->name = fkconstraint->constr_name;
- newcon->contype = CONSTR_FOREIGN;
- newcon->refrelid = RelationGetRelid(pkrel);
- newcon->qual = (Node *) fkconstraint;
-
- tab->constraints = lappend(tab->constraints, newcon);
+ pfeqoperators[i] = pfeqop;
+ ppeqoperators[i] = ppeqop;
+ ffeqoperators[i] = ffeqop;
}
/*
@@ -4254,6 +4051,9 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
* constraint */
RelationGetRelid(pkrel),
pkattnum,
+ pfeqoperators,
+ ppeqoperators,
+ ffeqoperators,
numpks,
fkconstraint->fk_upd_action,
fkconstraint->fk_del_action,
@@ -4269,6 +4069,24 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
createForeignKeyTriggers(rel, fkconstraint, constrOid);
/*
+ * Tell Phase 3 to check that the constraint is satisfied by existing rows
+ * (we can skip this during table creation).
+ */
+ if (!fkconstraint->skip_validation)
+ {
+ NewConstraint *newcon;
+
+ newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
+ newcon->name = fkconstraint->constr_name;
+ newcon->contype = CONSTR_FOREIGN;
+ newcon->refrelid = RelationGetRelid(pkrel);
+ newcon->conid = constrOid;
+ newcon->qual = (Node *) fkconstraint;
+
+ tab->constraints = lappend(tab->constraints, newcon);
+ }
+
+ /*
* Close pk table, but keep lock until we've committed.
*/
heap_close(pkrel, NoLock);
@@ -4526,25 +4344,15 @@ transformFkeyCheckAttrs(Relation pkrel,
static void
validateForeignKeyConstraint(FkConstraint *fkconstraint,
Relation rel,
- Relation pkrel)
+ Relation pkrel,
+ Oid constraintOid)
{
HeapScanDesc scan;
HeapTuple tuple;
Trigger trig;
- ListCell *list;
- int count;
/*
- * See if we can do it with a single LEFT JOIN query. A FALSE result
- * indicates we must proceed with the fire-the-trigger method.
- */
- if (RI_Initial_Check(fkconstraint, rel, pkrel))
- return;
-
- /*
- * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
- * if that tuple had just been inserted. If any of those fail, it should
- * ereport(ERROR) and that's that.
+ * Build a trigger call structure; we'll need it either way.
*/
MemSet(&trig, 0, sizeof(trig));
trig.tgoid = InvalidOid;
@@ -4552,35 +4360,23 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint,
trig.tgenabled = TRUE;
trig.tgisconstraint = TRUE;
trig.tgconstrrelid = RelationGetRelid(pkrel);
+ trig.tgconstraint = constraintOid;
trig.tgdeferrable = FALSE;
trig.tginitdeferred = FALSE;
+ /* we needn't fill in tgargs */
- trig.tgargs = (char **) palloc(sizeof(char *) *
- (4 + list_length(fkconstraint->fk_attrs)
- + list_length(fkconstraint->pk_attrs)));
-
- trig.tgargs[0] = trig.tgname;
- trig.tgargs[1] = RelationGetRelationName(rel);
- trig.tgargs[2] = RelationGetRelationName(pkrel);
- trig.tgargs[3] = fkMatchTypeToString(fkconstraint->fk_matchtype);
- count = 4;
- foreach(list, fkconstraint->fk_attrs)
- {
- char *fk_at = strVal(lfirst(list));
-
- trig.tgargs[count] = fk_at;
- count += 2;
- }
- count = 5;
- foreach(list, fkconstraint->pk_attrs)
- {
- char *pk_at = strVal(lfirst(list));
-
- trig.tgargs[count] = pk_at;
- count += 2;
- }
- trig.tgnargs = count - 1;
+ /*
+ * See if we can do it with a single LEFT JOIN query. A FALSE result
+ * indicates we must proceed with the fire-the-trigger method.
+ */
+ if (RI_Initial_Check(&trig, rel, pkrel))
+ return;
+ /*
+ * Scan through each tuple, calling RI_FKey_check_ins (insert trigger) as
+ * if that tuple had just been inserted. If any of those fail, it should
+ * ereport(ERROR) and that's that.
+ */
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
@@ -4613,18 +4409,13 @@ validateForeignKeyConstraint(FkConstraint *fkconstraint,
}
heap_endscan(scan);
-
- pfree(trig.tgargs);
}
static void
CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint,
- ObjectAddress *constrobj, ObjectAddress *trigobj,
- bool on_insert)
+ Oid constraintOid, bool on_insert)
{
CreateTrigStmt *fk_trigger;
- ListCell *fk_attr;
- ListCell *pk_attr;
fk_trigger = makeNode(CreateTrigStmt);
fk_trigger->trigname = fkconstraint->constr_name;
@@ -4649,32 +4440,9 @@ CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint,
fk_trigger->deferrable = fkconstraint->deferrable;
fk_trigger->initdeferred = fkconstraint->initdeferred;
fk_trigger->constrrel = fkconstraint->pktable;
-
fk_trigger->args = NIL;
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(fkconstraint->constr_name));
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(myRel->relname));
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(fkconstraint->pktable->relname));
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(fkMatchTypeToString(fkconstraint->fk_matchtype)));
- if (list_length(fkconstraint->fk_attrs) != list_length(fkconstraint->pk_attrs))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_FOREIGN_KEY),
- errmsg("number of referencing and referenced columns for foreign key disagree")));
-
- forboth(fk_attr, fkconstraint->fk_attrs,
- pk_attr, fkconstraint->pk_attrs)
- {
- fk_trigger->args = lappend(fk_trigger->args, lfirst(fk_attr));
- fk_trigger->args = lappend(fk_trigger->args, lfirst(pk_attr));
- }
- trigobj->objectId = CreateTrigger(fk_trigger, true);
-
- /* Register dependency from trigger to constraint */
- recordDependencyOn(trigobj, constrobj, DEPENDENCY_INTERNAL);
+ (void) CreateTrigger(fk_trigger, constraintOid);
/* Make changes-so-far visible */
CommandCounterIncrement();
@@ -4685,14 +4453,10 @@ CreateFKCheckTrigger(RangeVar *myRel, FkConstraint *fkconstraint,
*/
static void
createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
- Oid constrOid)
+ Oid constraintOid)
{
RangeVar *myRel;
CreateTrigStmt *fk_trigger;
- ListCell *fk_attr;
- ListCell *pk_attr;
- ObjectAddress trigobj,
- constrobj;
/*
* Reconstruct a RangeVar for my relation (not passed in, unfortunately).
@@ -4700,15 +4464,6 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
myRel = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
pstrdup(RelationGetRelationName(rel)));
- /*
- * Preset objectAddress fields
- */
- constrobj.classId = ConstraintRelationId;
- constrobj.objectId = constrOid;
- constrobj.objectSubId = 0;
- trigobj.classId = TriggerRelationId;
- trigobj.objectSubId = 0;
-
/* Make changes-so-far visible */
CommandCounterIncrement();
@@ -4716,8 +4471,8 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
* Build and execute a CREATE CONSTRAINT TRIGGER statement for the CHECK
* action for both INSERTs and UPDATEs on the referencing table.
*/
- CreateFKCheckTrigger(myRel, fkconstraint, &constrobj, &trigobj, true);
- CreateFKCheckTrigger(myRel, fkconstraint, &constrobj, &trigobj, false);
+ CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, true);
+ CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, false);
/*
* Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
@@ -4765,27 +4520,9 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
(int) fkconstraint->fk_del_action);
break;
}
-
fk_trigger->args = NIL;
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(fkconstraint->constr_name));
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(myRel->relname));
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(fkconstraint->pktable->relname));
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(fkMatchTypeToString(fkconstraint->fk_matchtype)));
- forboth(fk_attr, fkconstraint->fk_attrs,
- pk_attr, fkconstraint->pk_attrs)
- {
- fk_trigger->args = lappend(fk_trigger->args, lfirst(fk_attr));
- fk_trigger->args = lappend(fk_trigger->args, lfirst(pk_attr));
- }
-
- trigobj.objectId = CreateTrigger(fk_trigger, true);
- /* Register dependency from trigger to constraint */
- recordDependencyOn(&trigobj, &constrobj, DEPENDENCY_INTERNAL);
+ (void) CreateTrigger(fk_trigger, constraintOid);
/* Make changes-so-far visible */
CommandCounterIncrement();
@@ -4835,49 +4572,9 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
(int) fkconstraint->fk_upd_action);
break;
}
-
fk_trigger->args = NIL;
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(fkconstraint->constr_name));
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(myRel->relname));
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(fkconstraint->pktable->relname));
- fk_trigger->args = lappend(fk_trigger->args,
- makeString(fkMatchTypeToString(fkconstraint->fk_matchtype)));
- forboth(fk_attr, fkconstraint->fk_attrs,
- pk_attr, fkconstraint->pk_attrs)
- {
- fk_trigger->args = lappend(fk_trigger->args, lfirst(fk_attr));
- fk_trigger->args = lappend(fk_trigger->args, lfirst(pk_attr));
- }
-
- trigobj.objectId = CreateTrigger(fk_trigger, true);
- /* Register dependency from trigger to constraint */
- recordDependencyOn(&trigobj, &constrobj, DEPENDENCY_INTERNAL);
-}
-
-/*
- * fkMatchTypeToString -
- * convert FKCONSTR_MATCH_xxx code to string to use in trigger args
- */
-static char *
-fkMatchTypeToString(char match_type)
-{
- switch (match_type)
- {
- case FKCONSTR_MATCH_FULL:
- return pstrdup("FULL");
- case FKCONSTR_MATCH_PARTIAL:
- return pstrdup("PARTIAL");
- case FKCONSTR_MATCH_UNSPECIFIED:
- return pstrdup("UNSPECIFIED");
- default:
- elog(ERROR, "unrecognized match type: %d",
- (int) match_type);
- }
- return NULL; /* can't get here */
+ (void) CreateTrigger(fk_trigger, constraintOid);
}
/*