Warning: This patch is only a work in work in progress. Current Status:
This patch modifies postgres's current behavior by creating foreign-key triggers on not only the source and referenced tables, but also the children of the referenced table. It modifies the source triggers, removing the ONLY keyword when looking up the referenced key. Shortcomings: The triggers are only created when the foreign key is created, so any new tables that inherit from the referenced table will not have the triggers. This can be fixed fairly easily. When removing the ONLY clause on the foreign key checks, I also had to remove the FOR SHARE OF x part. This was in the following functions: RI_FKey_check, ri_Check_Pk_Match, RI_FKey_noaction_del, RI_FKey_noaction_upd, RI_FKey_restrict_del. I don't really understand the significance of this. There is no way to turn off the new behavior, which will likely cause breakages in existing applications. If this behavior was made optional on a per foreign key basis, with the current syntax being backwards compatible, then this would not be an issue. Inherited relations don't share primary key indexes, so there is the possibility of duplicates. Can this be fixed by putting triggers on the inherited tables to ensure they aren't duplicating a primary key? Can/should indexes, constraints, triggers be shared between inherited tables? Would this be a lot of work, and is it desired? Does it need to be configurable per index, or per inheritance? Matt Newell, Blur Studio
? GNUmakefile ? config.log ? config.status ? inherit_fkey.diff ? pre_upgrade.sql ? src/Makefile.global ? src/backend/postgres ? src/backend/catalog/postgres.bki ? src/backend/catalog/postgres.description ? src/backend/utils/mb/conversion_procs/conversion_create.sql ? src/backend/utils/mb/conversion_procs/ascii_and_mic/libascii_and_mic.so.0.0 ? src/backend/utils/mb/conversion_procs/cyrillic_and_mic/libcyrillic_and_mic.so.0.0 ? src/backend/utils/mb/conversion_procs/euc_cn_and_mic/libeuc_cn_and_mic.so.0.0 ? src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/libeuc_jp_and_sjis.so.0.0 ? src/backend/utils/mb/conversion_procs/euc_kr_and_mic/libeuc_kr_and_mic.so.0.0 ? src/backend/utils/mb/conversion_procs/euc_tw_and_big5/libeuc_tw_and_big5.so.0.0 ? src/backend/utils/mb/conversion_procs/latin2_and_win1250/liblatin2_and_win1250.so.0.0 ? src/backend/utils/mb/conversion_procs/latin_and_mic/liblatin_and_mic.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_ascii/libutf8_and_ascii.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_big5/libutf8_and_big5.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/libutf8_and_cyrillic.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/libutf8_and_euc_cn.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/libutf8_and_euc_jp.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/libutf8_and_euc_kr.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/libutf8_and_euc_tw.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_gb18030/libutf8_and_gb18030.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_gbk/libutf8_and_gbk.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859/libutf8_and_iso8859.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/libutf8_and_iso8859_1.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_johab/libutf8_and_johab.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_sjis/libutf8_and_sjis.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_uhc/libutf8_and_uhc.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win1250/libutf8_and_win1250.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win1252/libutf8_and_win1252.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win1256/libutf8_and_win1256.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win1258/libutf8_and_win1258.so.0.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win874/libutf8_and_win874.so.0.0 ? src/bin/initdb/initdb ? src/bin/ipcclean/ipcclean ? src/bin/pg_config/pg_config ? src/bin/pg_controldata/pg_controldata ? src/bin/pg_ctl/pg_ctl ? src/bin/pg_dump/pg_dump ? src/bin/pg_dump/pg_dumpall ? src/bin/pg_dump/pg_restore ? src/bin/pg_resetxlog/pg_resetxlog ? src/bin/psql/psql ? src/bin/scripts/clusterdb ? src/bin/scripts/createdb ? src/bin/scripts/createlang ? src/bin/scripts/createuser ? src/bin/scripts/dropdb ? src/bin/scripts/droplang ? src/bin/scripts/dropuser ? src/bin/scripts/reindexdb ? src/bin/scripts/vacuumdb ? src/include/pg_config.h ? src/include/stamp-h ? src/interfaces/ecpg/compatlib/libecpg_compat.so.2.1 ? src/interfaces/ecpg/ecpglib/libecpg.so.5.1 ? src/interfaces/ecpg/pgtypeslib/libpgtypes.so.2.1 ? src/interfaces/ecpg/preproc/ecpg ? src/interfaces/libpq/libpq.so.4.1 ? src/pl/plpgsql/src/libplpgsql.so.1.0 ? src/port/pg_config_paths.h ? src/test/regress/libregress.so.0.0 ? src/test/regress/log ? src/test/regress/pg_regress ? src/test/regress/regression.diffs ? src/test/regress/regression.out ? src/test/regress/results ? src/test/regress/testtablespace ? src/test/regress/tmp_check ? src/test/regress/expected/constraints.out ? src/test/regress/expected/copy.out ? src/test/regress/expected/create_function_1.out ? src/test/regress/expected/create_function_2.out ? src/test/regress/expected/misc.out ? src/test/regress/expected/tablespace.out ? src/test/regress/sql/constraints.sql ? src/test/regress/sql/copy.sql ? src/test/regress/sql/create_function_1.sql ? src/test/regress/sql/create_function_2.sql ? src/test/regress/sql/misc.sql ? src/test/regress/sql/tablespace.sql ? src/timezone/zic Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/tablecmds.c,v retrieving revision 1.174 diff -u -3 -p -u -r1.174 tablecmds.c --- src/backend/commands/tablecmds.c 15 Oct 2005 02:49:15 -0000 1.174 +++ src/backend/commands/tablecmds.c 31 Oct 2005 01:09:24 -0000 @@ -4434,84 +4434,56 @@ CreateFKCheckTrigger(RangeVar *myRel, Fk } /* - * Create the triggers that implement an FK constraint. + * This is a helper function for createForeignKeyTriggers. It prepares a CreateTrigStmt + * object for calling CreateTrigger. + * action_char must be either 'u' or 'd' */ -static void -createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, - Oid constrOid) +static CreateTrigStmt * +prepareCreateTrigStmt(RangeVar * myRel, FkConstraint * fkconstraint, Oid constrOid, RangeVar * refRel, char action_char) { - RangeVar *myRel; CreateTrigStmt *fk_trigger; ListCell *fk_attr; ListCell *pk_attr; - ObjectAddress trigobj, - constrobj; - - /* - * Reconstruct a RangeVar for my relation (not passed in, unfortunately). - */ - 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(); + Assert( (action_char=='u') || (action_char=='d') ); - /* - * 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); - - /* - * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON - * DELETE action on the referenced table. - */ fk_trigger = makeNode(CreateTrigStmt); fk_trigger->trigname = fkconstraint->constr_name; - fk_trigger->relation = fkconstraint->pktable; + fk_trigger->relation = refRel; fk_trigger->before = false; fk_trigger->row = true; - fk_trigger->actions[0] = 'd'; + fk_trigger->actions[0] = action_char; fk_trigger->actions[1] = '\0'; fk_trigger->isconstraint = true; fk_trigger->constrrel = myRel; - switch (fkconstraint->fk_del_action) + char action = action_char == 'd' ? fkconstraint->fk_del_action : fkconstraint->fk_upd_action; + switch (action) { case FKCONSTR_ACTION_NOACTION: fk_trigger->deferrable = fkconstraint->deferrable; fk_trigger->initdeferred = fkconstraint->initdeferred; - fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del"); + fk_trigger->funcname = SystemFuncName(action_char == 'd' ? "RI_FKey_noaction_del" : "RI_FKey_noaction_upd"); break; case FKCONSTR_ACTION_RESTRICT: fk_trigger->deferrable = false; fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del"); + fk_trigger->funcname = SystemFuncName(action_char == 'd' ? "RI_FKey_restrict_del" : "RI_FKey_restrict_upd"); break; case FKCONSTR_ACTION_CASCADE: fk_trigger->deferrable = false; fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del"); + fk_trigger->funcname = SystemFuncName(action_char == 'd' ? "RI_FKey_cascade_del" : "RI_FKey_cascade_upd"); break; case FKCONSTR_ACTION_SETNULL: fk_trigger->deferrable = false; fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del"); + fk_trigger->funcname = SystemFuncName(action_char == 'd' ? "RI_FKey_setnull_del" : "RI_FKey_setnull_upd"); break; case FKCONSTR_ACTION_SETDEFAULT: fk_trigger->deferrable = false; fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del"); + fk_trigger->funcname = SystemFuncName(action_char == 'd' ? "RI_FKey_setdefault_del" : "RI_FKey_setdefault_upd"); break; default: elog(ERROR, "unrecognized FK action type: %d", @@ -4525,7 +4497,7 @@ createForeignKeyTriggers(Relation rel, F fk_trigger->args = lappend(fk_trigger->args, makeString(myRel->relname)); fk_trigger->args = lappend(fk_trigger->args, - makeString(fkconstraint->pktable->relname)); + makeString(refRel->relname)); fk_trigger->args = lappend(fk_trigger->args, makeString(fkMatchTypeToString(fkconstraint->fk_matchtype))); forboth(fk_attr, fkconstraint->fk_attrs, @@ -4534,6 +4506,56 @@ createForeignKeyTriggers(Relation rel, F fk_trigger->args = lappend(fk_trigger->args, lfirst(fk_attr)); fk_trigger->args = lappend(fk_trigger->args, lfirst(pk_attr)); } + return fk_trigger; +} + +/* + * Create the triggers that implement an FK constraint. + */ +static void +createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, + Oid constrOid) +{ + RangeVar *myRel; + CreateTrigStmt *fk_trigger; + ObjectAddress trigobj, + constrobj; + List *children; + ListCell *child; + + /* this routine is actually in the planner */ + children = find_all_inheritors(RangeVarGetRelid(fkconstraint->pktable, false)); + + /* + * Reconstruct a RangeVar for my relation (not passed in, unfortunately). + */ + 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(); + + /* + * 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); + + /* + * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON + * DELETE action on the referenced table. + */ + fk_trigger = prepareCreateTrigStmt(myRel,fkconstraint,constrOid,fkconstraint->pktable,'d'); trigobj.objectId = CreateTrigger(fk_trigger, true); @@ -4547,68 +4569,71 @@ createForeignKeyTriggers(Relation rel, F * Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON * UPDATE action on the referenced table. */ - fk_trigger = makeNode(CreateTrigStmt); - fk_trigger->trigname = fkconstraint->constr_name; - fk_trigger->relation = fkconstraint->pktable; - fk_trigger->before = false; - fk_trigger->row = true; - fk_trigger->actions[0] = 'u'; - fk_trigger->actions[1] = '\0'; - fk_trigger->isconstraint = true; - fk_trigger->constrrel = myRel; - switch (fkconstraint->fk_upd_action) - { - case FKCONSTR_ACTION_NOACTION: - fk_trigger->deferrable = fkconstraint->deferrable; - fk_trigger->initdeferred = fkconstraint->initdeferred; - fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd"); - break; - case FKCONSTR_ACTION_RESTRICT: - fk_trigger->deferrable = false; - fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd"); - break; - case FKCONSTR_ACTION_CASCADE: - fk_trigger->deferrable = false; - fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd"); - break; - case FKCONSTR_ACTION_SETNULL: - fk_trigger->deferrable = false; - fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd"); - break; - case FKCONSTR_ACTION_SETDEFAULT: - fk_trigger->deferrable = false; - fk_trigger->initdeferred = false; - fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd"); - break; - default: - elog(ERROR, "unrecognized FK action type: %d", - (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)); - } + fk_trigger = prepareCreateTrigStmt(myRel,fkconstraint,constrOid,fkconstraint->pktable,'u'); trigobj.objectId = CreateTrigger(fk_trigger, true); /* Register dependency from trigger to constraint */ recordDependencyOn(&trigobj, &constrobj, DEPENDENCY_INTERNAL); + + /* Make changes-so-far visible */ + CommandCounterIncrement(); + + /* + * find_all_inheritors does the recursive search of the inheritance + * hierarchy, so all we have to do is process all of the relids in the + * list that it returns. + */ + foreach(child, children) + { + Oid childrelid; + Relation childrel; + RangeVar * childrv; + ObjectAddress childrelobj; + + childrelid = lfirst_oid(child); + childrel = relation_open(childrelid, AccessExclusiveLock); + + childrv = makeRangeVar(get_namespace_name(RelationGetNamespace(childrel)), + pstrdup(RelationGetRelationName(childrel))); + + /* + * First, add a dependancy between the table and the constraint + * This is done for the original(opposed to children) table + * in CreateConstraintEntry + */ + childrelobj.classId = RelationRelationId; + childrelobj.objectId = childrelid; + childrelobj.objectSubId = 0; + + recordDependencyOn(&constrobj, &childrelobj, DEPENDENCY_NORMAL); + + /* + * Create the update trigger + */ + fk_trigger = prepareCreateTrigStmt(myRel,fkconstraint,constrOid,childrv,'u'); + trigobj.objectId = CreateTrigger(fk_trigger, true); + + /* Register dependency from trigger to constraint */ + recordDependencyOn(&trigobj, &constrobj, DEPENDENCY_INTERNAL); + + /* Make changes-so-far visible */ + CommandCounterIncrement(); + + /* + * Create the delete trigger + */ + fk_trigger = prepareCreateTrigStmt(myRel,fkconstraint,constrOid,childrv,'d'); + trigobj.objectId = CreateTrigger(fk_trigger, true); + + /* Register dependency from trigger to constraint */ + recordDependencyOn(&trigobj, &constrobj, DEPENDENCY_INTERNAL); + + /* Make changes-so-far visible */ + CommandCounterIncrement(); + + relation_close(childrel, AccessExclusiveLock); + } } /* Index: src/backend/utils/adt/ri_triggers.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v retrieving revision 1.81 diff -u -3 -p -u -r1.81 ri_triggers.c --- src/backend/utils/adt/ri_triggers.c 15 Oct 2005 02:49:29 -0000 1.81 +++ src/backend/utils/adt/ri_triggers.c 31 Oct 2005 01:09:24 -0000 @@ -266,7 +266,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(pkrelname, pk_rel); - snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x FOR SHARE OF x", + snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x", pkrelname); /* Prepare and save the plan */ @@ -399,7 +399,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(pkrelname, pk_rel); - snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x", pkrelname); + snprintf(querystr, sizeof(querystr), "SELECT 1 FROM %s x", pkrelname); querysep = "WHERE"; for (i = 0; i < qkey.nkeypairs; i++) { @@ -411,7 +411,6 @@ RI_FKey_check(PG_FUNCTION_ARGS) queryoids[i] = SPI_gettypeid(fk_rel->rd_att, qkey.keypair[i][RI_KEYPAIR_FK_IDX]); } - strcat(querystr, " FOR SHARE OF x"); /* Prepare and save the plan */ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids, @@ -560,7 +559,7 @@ ri_Check_Pk_Match(Relation pk_rel, Relat * ---------- */ quoteRelationName(pkrelname, pk_rel); - snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x", pkrelname); + snprintf(querystr, sizeof(querystr), "SELECT 1 FROM %s x", pkrelname); querysep = "WHERE"; for (i = 0; i < qkey.nkeypairs; i++) { @@ -572,7 +571,6 @@ ri_Check_Pk_Match(Relation pk_rel, Relat queryoids[i] = SPI_gettypeid(pk_rel->rd_att, qkey.keypair[i][RI_KEYPAIR_PK_IDX]); } - strcat(querystr, " FOR SHARE OF x"); /* Prepare and save the plan */ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids, @@ -716,7 +714,7 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x", fkrelname); + snprintf(querystr, sizeof(querystr), "SELECT 1 FROM %s x", fkrelname); querysep = "WHERE"; for (i = 0; i < qkey.nkeypairs; i++) { @@ -728,7 +726,6 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) queryoids[i] = SPI_gettypeid(pk_rel->rd_att, qkey.keypair[i][RI_KEYPAIR_PK_IDX]); } - strcat(querystr, " FOR SHARE OF x"); /* Prepare and save the plan */ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids, @@ -905,7 +902,7 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x", fkrelname); + snprintf(querystr, sizeof(querystr), "SELECT 1 FROM %s x", fkrelname); querysep = "WHERE"; for (i = 0; i < qkey.nkeypairs; i++) { @@ -917,7 +914,6 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) queryoids[i] = SPI_gettypeid(pk_rel->rd_att, qkey.keypair[i][RI_KEYPAIR_PK_IDX]); } - strcat(querystr, " FOR SHARE OF x"); /* Prepare and save the plan */ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids, @@ -1063,7 +1059,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "DELETE FROM ONLY %s", fkrelname); + snprintf(querystr, sizeof(querystr), "DELETE FROM %s", fkrelname); querysep = "WHERE"; for (i = 0; i < qkey.nkeypairs; i++) { @@ -1239,7 +1235,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "UPDATE ONLY %s SET", fkrelname); + snprintf(querystr, sizeof(querystr), "UPDATE %s SET", fkrelname); qualstr[0] = '\0'; querysep = ""; qualsep = "WHERE"; @@ -1411,7 +1407,7 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x", fkrelname); + snprintf(querystr, sizeof(querystr), "SELECT 1 FROM %s x", fkrelname); querysep = "WHERE"; for (i = 0; i < qkey.nkeypairs; i++) { @@ -1423,7 +1419,6 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) queryoids[i] = SPI_gettypeid(pk_rel->rd_att, qkey.keypair[i][RI_KEYPAIR_PK_IDX]); } - strcat(querystr, " FOR SHARE OF x"); /* Prepare and save the plan */ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids, @@ -1590,7 +1585,7 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x", fkrelname); + snprintf(querystr, sizeof(querystr), "SELECT 1 FROM %s x", fkrelname); querysep = "WHERE"; for (i = 0; i < qkey.nkeypairs; i++) { @@ -1602,7 +1597,6 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) queryoids[i] = SPI_gettypeid(pk_rel->rd_att, qkey.keypair[i][RI_KEYPAIR_PK_IDX]); } - strcat(querystr, " FOR SHARE OF x"); /* Prepare and save the plan */ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids, @@ -1751,7 +1745,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "UPDATE ONLY %s SET", fkrelname); + snprintf(querystr, sizeof(querystr), "UPDATE %s SET", fkrelname); qualstr[0] = '\0'; querysep = ""; qualsep = "WHERE"; @@ -1951,7 +1945,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "UPDATE ONLY %s SET", fkrelname); + snprintf(querystr, sizeof(querystr), "UPDATE %s SET", fkrelname); qualstr[0] = '\0'; querysep = ""; qualsep = "WHERE"; @@ -2132,7 +2126,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "UPDATE ONLY %s SET", fkrelname); + snprintf(querystr, sizeof(querystr), "UPDATE %s SET", fkrelname); qualstr[0] = '\0'; querysep = ""; qualsep = "WHERE"; @@ -2324,7 +2318,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) * ---------- */ quoteRelationName(fkrelname, fk_rel); - snprintf(querystr, sizeof(querystr), "UPDATE ONLY %s SET", fkrelname); + snprintf(querystr, sizeof(querystr), "UPDATE %s SET", fkrelname); qualstr[0] = '\0'; querysep = ""; qualsep = "WHERE"; @@ -2622,7 +2616,7 @@ RI_Initial_Check(FkConstraint *fkconstra quoteRelationName(pkrelname, pkrel); quoteRelationName(relname, rel); snprintf(querystr + strlen(querystr), sizeof(querystr) - strlen(querystr), - " FROM ONLY %s fk LEFT OUTER JOIN ONLY %s pk ON (", + " FROM %s fk LEFT OUTER JOIN ONLY %s pk ON (", relname, pkrelname); sep = "";
---------------------------(end of broadcast)--------------------------- TIP 3: Have you checked our extensive FAQ? http://www.postgresql.org/docs/faq