Commit 789ddcb5 authored by Tom Lane's avatar Tom Lane

Add tgconstrrelid to stored Trigger structures, make RI trigger functions

depend on this rather than the trigger argument strings to locate the
other relation to test.  This makes RI triggers function properly in
the presence of schemas and temp tables.  Along the way, fix bogus lack
of locking in RI triggers, handle quoting of names fully correctly,
compute required sizes of query buffers with some semblance of accuracy.
parent 6a25cd6b
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.21 2002/03/22 19:20:32 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/trigger.sgml,v 1.22 2002/04/01 22:36:06 tgl Exp $
--> -->
<chapter id="triggers"> <chapter id="triggers">
...@@ -374,6 +374,7 @@ typedef struct Trigger ...@@ -374,6 +374,7 @@ typedef struct Trigger
int16 tgtype; int16 tgtype;
bool tgenabled; bool tgenabled;
bool tgisconstraint; bool tgisconstraint;
Oid tgconstrrelid;
bool tgdeferrable; bool tgdeferrable;
bool tginitdeferred; bool tginitdeferred;
int16 tgnargs; int16 tgnargs;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.170 2002/04/01 04:35:38 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.171 2002/04/01 22:36:09 tgl Exp $
* *
* NOTES * NOTES
* The PerformAddAttribute() code, like most of the relation * The PerformAddAttribute() code, like most of the relation
...@@ -1639,9 +1639,6 @@ AlterTableAddConstraint(Oid myrelid, ...@@ -1639,9 +1639,6 @@ AlterTableAddConstraint(Oid myrelid,
!isTempNamespace(RelationGetNamespace(rel))) !isTempNamespace(RelationGetNamespace(rel)))
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint."); elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint.");
/* Don't need pkrel open anymore, but hold lock */
heap_close(pkrel, NoLock);
/* /*
* First we check for limited correctness of the * First we check for limited correctness of the
* constraint. * constraint.
...@@ -1651,34 +1648,30 @@ AlterTableAddConstraint(Oid myrelid, ...@@ -1651,34 +1648,30 @@ AlterTableAddConstraint(Oid myrelid,
* referenced relation, and that the column datatypes * referenced relation, and that the column datatypes
* are comparable. * are comparable.
* *
* Scan through each tuple, calling the RI_FKey_Match_Ins * Scan through each tuple, calling RI_FKey_check_ins
* (insert trigger) as if that tuple had just been * (insert trigger) as if that tuple had just been
* inserted. If any of those fail, it should * inserted. If any of those fail, it should
* elog(ERROR) and that's that. * elog(ERROR) and that's that.
*/ */
MemSet(&trig, 0, sizeof(trig));
trig.tgoid = 0; trig.tgoid = InvalidOid;
if (fkconstraint->constr_name) if (fkconstraint->constr_name)
trig.tgname = fkconstraint->constr_name; trig.tgname = fkconstraint->constr_name;
else else
trig.tgname = "<unknown>"; trig.tgname = "<unknown>";
trig.tgfoid = 0;
trig.tgtype = 0;
trig.tgenabled = TRUE; trig.tgenabled = TRUE;
trig.tgisconstraint = TRUE; trig.tgisconstraint = TRUE;
trig.tginitdeferred = FALSE; trig.tgconstrrelid = RelationGetRelid(pkrel);
trig.tgdeferrable = FALSE; trig.tgdeferrable = FALSE;
trig.tginitdeferred = FALSE;
trig.tgargs = (char **) palloc( trig.tgargs = (char **) palloc(
sizeof(char *) * (4 + length(fkconstraint->fk_attrs) sizeof(char *) * (4 + length(fkconstraint->fk_attrs)
+ length(fkconstraint->pk_attrs))); + length(fkconstraint->pk_attrs)));
if (fkconstraint->constr_name) trig.tgargs[0] = trig.tgname;
trig.tgargs[0] = fkconstraint->constr_name; trig.tgargs[1] = RelationGetRelationName(rel);
else trig.tgargs[2] = RelationGetRelationName(pkrel);
trig.tgargs[0] = "<unknown>";
trig.tgargs[1] = pstrdup(RelationGetRelationName(rel));
trig.tgargs[2] = fkconstraint->pktable->relname;
trig.tgargs[3] = fkconstraint->match_type; trig.tgargs[3] = fkconstraint->match_type;
count = 4; count = 4;
foreach(list, fkconstraint->fk_attrs) foreach(list, fkconstraint->fk_attrs)
...@@ -1732,6 +1725,9 @@ AlterTableAddConstraint(Oid myrelid, ...@@ -1732,6 +1725,9 @@ AlterTableAddConstraint(Oid myrelid,
heap_endscan(scan); heap_endscan(scan);
pfree(trig.tgargs); pfree(trig.tgargs);
heap_close(pkrel, NoLock);
break; break;
} }
default: default:
......
...@@ -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
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.110 2002/03/31 06:26:30 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.111 2002/04/01 22:36:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -544,6 +544,7 @@ RelationBuildTriggers(Relation relation) ...@@ -544,6 +544,7 @@ RelationBuildTriggers(Relation relation)
build->tgtype = pg_trigger->tgtype; build->tgtype = pg_trigger->tgtype;
build->tgenabled = pg_trigger->tgenabled; build->tgenabled = pg_trigger->tgenabled;
build->tgisconstraint = pg_trigger->tgisconstraint; build->tgisconstraint = pg_trigger->tgisconstraint;
build->tgconstrrelid = pg_trigger->tgconstrrelid;
build->tgdeferrable = pg_trigger->tgdeferrable; build->tgdeferrable = pg_trigger->tgdeferrable;
build->tginitdeferred = pg_trigger->tginitdeferred; build->tginitdeferred = pg_trigger->tginitdeferred;
build->tgnargs = pg_trigger->tgnargs; build->tgnargs = pg_trigger->tgnargs;
...@@ -763,6 +764,8 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) ...@@ -763,6 +764,8 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
return false; return false;
if (trig1->tgisconstraint != trig2->tgisconstraint) if (trig1->tgisconstraint != trig2->tgisconstraint)
return false; return false;
if (trig1->tgconstrrelid != trig2->tgconstrrelid)
return false;
if (trig1->tgdeferrable != trig2->tgdeferrable) if (trig1->tgdeferrable != trig2->tgdeferrable)
return false; return false;
if (trig1->tginitdeferred != trig2->tginitdeferred) if (trig1->tginitdeferred != trig2->tginitdeferred)
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group * Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group
* Copyright 1999 Jan Wieck * Copyright 1999 Jan Wieck
* *
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.34 2002/04/01 02:02:34 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.35 2002/04/01 22:36:10 tgl Exp $
* *
* ---------- * ----------
*/ */
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "postgres.h" #include "postgres.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "executor/spi_priv.h" #include "executor/spi_priv.h"
...@@ -68,6 +69,9 @@ ...@@ -68,6 +69,9 @@
#define RI_PLAN_SETNULL_DEL_DOUPDATE 1 #define RI_PLAN_SETNULL_DEL_DOUPDATE 1
#define RI_PLAN_SETNULL_UPD_DOUPDATE 1 #define RI_PLAN_SETNULL_UPD_DOUPDATE 1
#define MAX_QUOTED_NAME_LEN (NAMEDATALEN*2+3)
#define MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2)
/* ---------- /* ----------
* RI_QueryKey * RI_QueryKey
...@@ -118,6 +122,8 @@ static HTAB *ri_opreq_cache = (HTAB *) NULL; ...@@ -118,6 +122,8 @@ static HTAB *ri_opreq_cache = (HTAB *) NULL;
* Local function prototypes * Local function prototypes
* ---------- * ----------
*/ */
static void quoteOneName(char *buffer, const char *name);
static void quoteRelationName(char *buffer, Relation rel);
static int ri_DetermineMatchType(char *str); static int ri_DetermineMatchType(char *str);
static int ri_NullCheck(Relation rel, HeapTuple tup, static int ri_NullCheck(Relation rel, HeapTuple tup,
RI_QueryKey *key, int pairidx); RI_QueryKey *key, int pairidx);
...@@ -138,19 +144,6 @@ static void *ri_FetchPreparedPlan(RI_QueryKey *key); ...@@ -138,19 +144,6 @@ static void *ri_FetchPreparedPlan(RI_QueryKey *key);
static void ri_HashPreparedPlan(RI_QueryKey *key, void *plan); static void ri_HashPreparedPlan(RI_QueryKey *key, void *plan);
/*
* very ugly, very temporary hack to allow RI triggers to find tables
* anywhere in the current search path. This is just so that the regression
* tests don't break with new search path code; we MUST find a more bullet
* proof solution before release.
*/
static Relation
kluge_openr(char *relationName, LOCKMODE lockmode)
{
return heap_openrv(makeRangeVar(NULL, relationName), lockmode);
}
/* ---------- /* ----------
* RI_FKey_check - * RI_FKey_check -
* *
...@@ -207,9 +200,12 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -207,9 +200,12 @@ RI_FKey_check(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the new * Get the relation descriptors of the FK and PK tables and the new
* tuple. * tuple.
*
* pk_rel is opened in RowShareLock mode since that's what our
* eventual SELECT FOR UPDATE will get on it.
*/ */
fk_rel = trigdata->tg_relation; fk_rel = trigdata->tg_relation;
pk_rel = kluge_openr(tgargs[RI_PK_RELNAME_ARGNO], NoLock); pk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
{ {
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
...@@ -221,16 +217,17 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -221,16 +217,17 @@ RI_FKey_check(PG_FUNCTION_ARGS)
new_row = trigdata->tg_trigtuple; new_row = trigdata->tg_trigtuple;
} }
/* /*
* We should not even consider checking the row if it is no longer * We should not even consider checking the row if it is no longer
* valid since it was either deleted (doesn't matter) or updated * valid since it was either deleted (doesn't matter) or updated
* (in which case it'll be checked with its final values). * (in which case it'll be checked with its final values).
*/ */
if (new_row) { if (new_row) {
if (!HeapTupleSatisfiesItself(new_row->t_data)) { if (!HeapTupleSatisfiesItself(new_row->t_data)) {
return PointerGetDatum(NULL); heap_close(pk_rel, RowShareLock);
} return PointerGetDatum(NULL);
} }
}
/* ---------- /* ----------
* SQL3 11.9 <referential constraint definition> * SQL3 11.9 <referential constraint definition>
...@@ -252,16 +249,17 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -252,16 +249,17 @@ RI_FKey_check(PG_FUNCTION_ARGS)
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char querystr[8192]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100];
char pkrelname[MAX_QUOTED_REL_NAME_LEN];
/* --------- /* ---------
* The query string built is * The query string built is
* SELECT 1 FROM ONLY <pktable> * SELECT 1 FROM ONLY <pktable>
* ---------- * ----------
*/ */
sprintf(querystr, "SELECT 1 FROM ONLY \"%s\" FOR UPDATE OF \"%s\"", quoteRelationName(pkrelname, pk_rel);
tgargs[RI_PK_RELNAME_ARGNO], sprintf(querystr, "SELECT 1 FROM ONLY %s x FOR UPDATE OF x",
tgargs[RI_PK_RELNAME_ARGNO]); pkrelname);
/* /*
* Prepare, save and remember the new plan. * Prepare, save and remember the new plan.
...@@ -278,8 +276,6 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -278,8 +276,6 @@ RI_FKey_check(PG_FUNCTION_ARGS)
elog(WARNING, "SPI_connect() failed in RI_FKey_check()"); elog(WARNING, "SPI_connect() failed in RI_FKey_check()");
SetUserId(RelationGetForm(pk_rel)->relowner); SetUserId(RelationGetForm(pk_rel)->relowner);
/* pk_rel is no longer neede OK ? */
heap_close(pk_rel, NoLock);
if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT) if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT)
elog(ERROR, "SPI_execp() failed in RI_FKey_check()"); elog(ERROR, "SPI_execp() failed in RI_FKey_check()");
...@@ -290,11 +286,13 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -290,11 +286,13 @@ RI_FKey_check(PG_FUNCTION_ARGS)
elog(ERROR, "%s referential integrity violation - " elog(ERROR, "%s referential integrity violation - "
"no rows found in %s", "no rows found in %s",
tgargs[RI_CONSTRAINT_NAME_ARGNO], tgargs[RI_CONSTRAINT_NAME_ARGNO],
tgargs[RI_PK_RELNAME_ARGNO]); RelationGetRelationName(pk_rel));
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); elog(WARNING, "SPI_finish() failed in RI_FKey_check()");
heap_close(pk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
} }
...@@ -322,7 +320,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -322,7 +320,7 @@ RI_FKey_check(PG_FUNCTION_ARGS)
* This is true for MATCH FULL, MATCH PARTIAL, and MATCH * This is true for MATCH FULL, MATCH PARTIAL, and MATCH
* <unspecified> * <unspecified>
*/ */
heap_close(pk_rel, NoLock); heap_close(pk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_SOME_NULL: case RI_KEYS_SOME_NULL:
...@@ -343,7 +341,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -343,7 +341,7 @@ RI_FKey_check(PG_FUNCTION_ARGS)
"MATCH FULL doesn't allow mixing of NULL " "MATCH FULL doesn't allow mixing of NULL "
"and NON-NULL key values", "and NON-NULL key values",
tgargs[RI_CONSTRAINT_NAME_ARGNO]); tgargs[RI_CONSTRAINT_NAME_ARGNO]);
heap_close(pk_rel, NoLock); heap_close(pk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_MATCH_TYPE_UNSPECIFIED: case RI_MATCH_TYPE_UNSPECIFIED:
...@@ -352,7 +350,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -352,7 +350,7 @@ RI_FKey_check(PG_FUNCTION_ARGS)
* MATCH <unspecified> - if ANY column is null, we * MATCH <unspecified> - if ANY column is null, we
* have a match. * have a match.
*/ */
heap_close(pk_rel, NoLock); heap_close(pk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_MATCH_TYPE_PARTIAL: case RI_MATCH_TYPE_PARTIAL:
...@@ -364,7 +362,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -364,7 +362,7 @@ RI_FKey_check(PG_FUNCTION_ARGS)
* writing a special version here) * writing a special version here)
*/ */
elog(ERROR, "MATCH PARTIAL not yet implemented"); elog(ERROR, "MATCH PARTIAL not yet implemented");
heap_close(pk_rel, NoLock); heap_close(pk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
} }
...@@ -393,9 +391,11 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -393,9 +391,11 @@ RI_FKey_check(PG_FUNCTION_ARGS)
*/ */
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char pkrelname[MAX_QUOTED_REL_NAME_LEN];
char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
/* ---------- /* ----------
...@@ -407,21 +407,20 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -407,21 +407,20 @@ RI_FKey_check(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "SELECT 1 FROM ONLY \"%s\"", quoteRelationName(pkrelname, pk_rel);
tgargs[RI_PK_RELNAME_ARGNO]); sprintf(querystr, "SELECT 1 FROM ONLY %s x", pkrelname);
querysep = "WHERE"; querysep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
sprintf(buf, " %s \"%s\" = $%d", querysep, quoteOneName(attname,
tgargs[5 + i * 2], i + 1); tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_PK_IDX]);
strcat(querystr, buf); sprintf(querystr + strlen(querystr), " %s %s = $%d",
querysep, attname, i+1);
querysep = "AND"; querysep = "AND";
queryoids[i] = SPI_gettypeid(fk_rel->rd_att, queryoids[i] = SPI_gettypeid(fk_rel->rd_att,
qkey.keypair[i][RI_KEYPAIR_FK_IDX]); qkey.keypair[i][RI_KEYPAIR_FK_IDX]);
} }
sprintf(buf, " FOR UPDATE OF \"%s\"", strcat(querystr, " FOR UPDATE OF x");
tgargs[RI_PK_RELNAME_ARGNO]);
strcat(querystr, buf);
/* /*
* Prepare, save and remember the new plan. * Prepare, save and remember the new plan.
...@@ -460,8 +459,6 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -460,8 +459,6 @@ RI_FKey_check(PG_FUNCTION_ARGS)
*/ */
SetUserId(RelationGetForm(pk_rel)->relowner); SetUserId(RelationGetForm(pk_rel)->relowner);
/* pk_rel is no longer needed OK ? */
heap_close(pk_rel, NoLock);
if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT) if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT)
elog(ERROR, "SPI_execp() failed in RI_FKey_check()"); elog(ERROR, "SPI_execp() failed in RI_FKey_check()");
...@@ -472,12 +469,14 @@ RI_FKey_check(PG_FUNCTION_ARGS) ...@@ -472,12 +469,14 @@ RI_FKey_check(PG_FUNCTION_ARGS)
elog(ERROR, "%s referential integrity violation - " elog(ERROR, "%s referential integrity violation - "
"key referenced from %s not found in %s", "key referenced from %s not found in %s",
tgargs[RI_CONSTRAINT_NAME_ARGNO], tgargs[RI_CONSTRAINT_NAME_ARGNO],
tgargs[RI_FK_RELNAME_ARGNO], RelationGetRelationName(fk_rel),
tgargs[RI_PK_RELNAME_ARGNO]); RelationGetRelationName(pk_rel));
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_check()"); elog(WARNING, "SPI_finish() failed in RI_FKey_check()");
heap_close(pk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -575,8 +574,11 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) ...@@ -575,8 +574,11 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the old * Get the relation descriptors of the FK and PK tables and the old
* tuple. * tuple.
*
* fk_rel is opened in RowShareLock mode since that's what our
* eventual SELECT FOR UPDATE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
...@@ -605,7 +607,7 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) ...@@ -605,7 +607,7 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
* No check - MATCH FULL means there cannot be any * No check - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -615,7 +617,6 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) ...@@ -615,7 +617,6 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
*/ */
break; break;
} }
heap_close(fk_rel, NoLock);
if (SPI_connect() != SPI_OK_CONNECT) if (SPI_connect() != SPI_OK_CONNECT)
elog(WARNING, "SPI_connect() failed in RI_FKey_noaction_del()"); elog(WARNING, "SPI_connect() failed in RI_FKey_noaction_del()");
...@@ -626,9 +627,11 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) ...@@ -626,9 +627,11 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
*/ */
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
/* ---------- /* ----------
...@@ -640,21 +643,20 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) ...@@ -640,21 +643,20 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "SELECT 1 FROM ONLY \"%s\"", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "SELECT 1 FROM ONLY %s x", fkrelname);
querysep = "WHERE"; querysep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
sprintf(buf, " %s \"%s\" = $%d", querysep, quoteOneName(attname,
tgargs[4 + i * 2], i + 1); tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
strcat(querystr, buf); sprintf(querystr + strlen(querystr), " %s %s = $%d",
querysep, attname, i+1);
querysep = "AND"; querysep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
qkey.keypair[i][RI_KEYPAIR_PK_IDX]); qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
} }
sprintf(buf, " FOR UPDATE OF \"%s\"", strcat(querystr, " FOR UPDATE OF x");
tgargs[RI_FK_RELNAME_ARGNO]);
strcat(querystr, buf);
/* /*
* Prepare, save and remember the new plan. * Prepare, save and remember the new plan.
...@@ -695,12 +697,14 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS) ...@@ -695,12 +697,14 @@ RI_FKey_noaction_del(PG_FUNCTION_ARGS)
elog(ERROR, "%s referential integrity violation - " elog(ERROR, "%s referential integrity violation - "
"key in %s still referenced from %s", "key in %s still referenced from %s",
tgargs[RI_CONSTRAINT_NAME_ARGNO], tgargs[RI_CONSTRAINT_NAME_ARGNO],
tgargs[RI_PK_RELNAME_ARGNO], RelationGetRelationName(pk_rel),
tgargs[RI_FK_RELNAME_ARGNO]); RelationGetRelationName(fk_rel));
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_del()"); elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_del()");
heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -781,8 +785,11 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) ...@@ -781,8 +785,11 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the new * Get the relation descriptors of the FK and PK tables and the new
* and old tuple. * and old tuple.
*
* fk_rel is opened in RowShareLock mode since that's what our
* eventual SELECT FOR UPDATE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
new_row = trigdata->tg_newtuple; new_row = trigdata->tg_newtuple;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
...@@ -812,7 +819,7 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) ...@@ -812,7 +819,7 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
* No check - MATCH FULL means there cannot be any * No check - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -822,14 +829,16 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) ...@@ -822,14 +829,16 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
*/ */
break; break;
} }
heap_close(fk_rel, NoLock);
/* /*
* No need to check anything if old and new keys are equal * No need to check anything if old and new keys are equal
*/ */
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey, if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
RI_KEYPAIR_PK_IDX)) RI_KEYPAIR_PK_IDX))
{
heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
}
if (SPI_connect() != SPI_OK_CONNECT) if (SPI_connect() != SPI_OK_CONNECT)
elog(WARNING, "SPI_connect() failed in RI_FKey_noaction_upd()"); elog(WARNING, "SPI_connect() failed in RI_FKey_noaction_upd()");
...@@ -840,9 +849,11 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) ...@@ -840,9 +849,11 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
*/ */
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
/* ---------- /* ----------
...@@ -854,21 +865,20 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) ...@@ -854,21 +865,20 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "SELECT 1 FROM ONLY \"%s\"", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "SELECT 1 FROM ONLY %s x", fkrelname);
querysep = "WHERE"; querysep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
sprintf(buf, " %s \"%s\" = $%d", querysep, quoteOneName(attname,
tgargs[4 + i * 2], i + 1); tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
strcat(querystr, buf); sprintf(querystr + strlen(querystr), " %s %s = $%d",
querysep, attname, i+1);
querysep = "AND"; querysep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
qkey.keypair[i][RI_KEYPAIR_PK_IDX]); qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
} }
sprintf(buf, " FOR UPDATE OF \"%s\"", strcat(querystr, " FOR UPDATE OF x");
tgargs[RI_FK_RELNAME_ARGNO]);
strcat(querystr, buf);
/* /*
* Prepare, save and remember the new plan. * Prepare, save and remember the new plan.
...@@ -909,12 +919,14 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS) ...@@ -909,12 +919,14 @@ RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
elog(ERROR, "%s referential integrity violation - " elog(ERROR, "%s referential integrity violation - "
"key in %s still referenced from %s", "key in %s still referenced from %s",
tgargs[RI_CONSTRAINT_NAME_ARGNO], tgargs[RI_CONSTRAINT_NAME_ARGNO],
tgargs[RI_PK_RELNAME_ARGNO], RelationGetRelationName(pk_rel),
tgargs[RI_FK_RELNAME_ARGNO]); RelationGetRelationName(fk_rel));
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_upd()"); elog(WARNING, "SPI_finish() failed in RI_FKey_noaction_upd()");
heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -991,11 +1003,14 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) ...@@ -991,11 +1003,14 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the old * Get the relation descriptors of the FK and PK tables and the old
* tuple. * tuple.
*
* fk_rel is opened in RowExclusiveLock mode since that's what our
* eventual DELETE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
fk_owner = RelationGetForm(fk_rel)->relowner;
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
fk_owner = RelationGetForm(fk_rel)->relowner;
switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
{ {
...@@ -1022,7 +1037,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) ...@@ -1022,7 +1037,7 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
* No check - MATCH FULL means there cannot be any * No check - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -1032,7 +1047,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) ...@@ -1032,7 +1047,6 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
*/ */
break; break;
} }
heap_close(fk_rel, NoLock);
if (SPI_connect() != SPI_OK_CONNECT) if (SPI_connect() != SPI_OK_CONNECT)
elog(WARNING, "SPI_connect() failed in RI_FKey_cascade_del()"); elog(WARNING, "SPI_connect() failed in RI_FKey_cascade_del()");
...@@ -1042,9 +1056,11 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) ...@@ -1042,9 +1056,11 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
*/ */
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
/* ---------- /* ----------
...@@ -1056,14 +1072,15 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) ...@@ -1056,14 +1072,15 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "DELETE FROM ONLY \"%s\"", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "DELETE FROM ONLY %s", fkrelname);
querysep = "WHERE"; querysep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
sprintf(buf, " %s \"%s\" = $%d", querysep, quoteOneName(attname,
tgargs[4 + i * 2], i + 1); tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
strcat(querystr, buf); sprintf(querystr + strlen(querystr), " %s %s = $%d",
querysep, attname, i+1);
querysep = "AND"; querysep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
qkey.keypair[i][RI_KEYPAIR_PK_IDX]); qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
...@@ -1108,6 +1125,8 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS) ...@@ -1108,6 +1125,8 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_del()"); elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_del()");
heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -1186,12 +1205,15 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) ...@@ -1186,12 +1205,15 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the new * Get the relation descriptors of the FK and PK tables and the new
* and old tuple. * and old tuple.
*
* fk_rel is opened in RowExclusiveLock mode since that's what our
* eventual UPDATE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
fk_owner = RelationGetForm(fk_rel)->relowner;
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
new_row = trigdata->tg_newtuple; new_row = trigdata->tg_newtuple;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
fk_owner = RelationGetForm(fk_rel)->relowner;
switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
{ {
...@@ -1218,7 +1240,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) ...@@ -1218,7 +1240,7 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
* No update - MATCH FULL means there cannot be any * No update - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -1228,14 +1250,16 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) ...@@ -1228,14 +1250,16 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
*/ */
break; break;
} }
heap_close(fk_rel, NoLock);
/* /*
* No need to do anything if old and new keys are equal * No need to do anything if old and new keys are equal
*/ */
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey, if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
RI_KEYPAIR_PK_IDX)) RI_KEYPAIR_PK_IDX))
{
heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
}
if (SPI_connect() != SPI_OK_CONNECT) if (SPI_connect() != SPI_OK_CONNECT)
elog(WARNING, "SPI_connect() failed in RI_FKey_cascade_upd()"); elog(WARNING, "SPI_connect() failed in RI_FKey_cascade_upd()");
...@@ -1246,11 +1270,13 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) ...@@ -1246,11 +1270,13 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
*/ */
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS * 2];
char qualstr[8192]; char qualstr[(MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char *qualsep; char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
const char *qualsep;
Oid queryoids[RI_MAX_NUMKEYS * 2]; Oid queryoids[RI_MAX_NUMKEYS * 2];
/* ---------- /* ----------
...@@ -1263,19 +1289,19 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) ...@@ -1263,19 +1289,19 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "UPDATE ONLY \"%s\" SET", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "UPDATE ONLY %s SET", fkrelname);
qualstr[0] = '\0'; qualstr[0] = '\0';
querysep = ""; querysep = "";
qualsep = "WHERE"; qualsep = "WHERE";
for (i = 0, j = qkey.nkeypairs; i < qkey.nkeypairs; i++, j++) for (i = 0, j = qkey.nkeypairs; i < qkey.nkeypairs; i++, j++)
{ {
sprintf(buf, "%s \"%s\" = $%d", querysep, quoteOneName(attname,
tgargs[4 + i * 2], i + 1); tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
strcat(querystr, buf); sprintf(querystr + strlen(querystr), "%s %s = $%d",
sprintf(buf, " %s \"%s\" = $%d", qualsep, querysep, attname, i+1);
tgargs[4 + i * 2], j + 1); sprintf(qualstr + strlen(qualstr), " %s %s = $%d",
strcat(qualstr, buf); qualsep, attname, j+1);
querysep = ","; querysep = ",";
qualsep = "AND"; qualsep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
...@@ -1332,6 +1358,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS) ...@@ -1332,6 +1358,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_upd()"); elog(WARNING, "SPI_finish() failed in RI_FKey_cascade_upd()");
heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -1415,11 +1443,14 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) ...@@ -1415,11 +1443,14 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the old * Get the relation descriptors of the FK and PK tables and the old
* tuple. * tuple.
*
* fk_rel is opened in RowShareLock mode since that's what our
* eventual SELECT FOR UPDATE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
fk_owner = RelationGetForm(fk_rel)->relowner;
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
fk_owner = RelationGetForm(fk_rel)->relowner;
switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
{ {
...@@ -1446,7 +1477,7 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) ...@@ -1446,7 +1477,7 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
* No check - MATCH FULL means there cannot be any * No check - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -1456,7 +1487,6 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) ...@@ -1456,7 +1487,6 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
*/ */
break; break;
} }
heap_close(fk_rel, NoLock);
if (SPI_connect() != SPI_OK_CONNECT) if (SPI_connect() != SPI_OK_CONNECT)
elog(WARNING, "SPI_connect() failed in RI_FKey_restrict_del()"); elog(WARNING, "SPI_connect() failed in RI_FKey_restrict_del()");
...@@ -1467,9 +1497,11 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) ...@@ -1467,9 +1497,11 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
*/ */
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
/* ---------- /* ----------
...@@ -1481,21 +1513,20 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) ...@@ -1481,21 +1513,20 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "SELECT 1 FROM ONLY \"%s\"", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "SELECT 1 FROM ONLY %s x", fkrelname);
querysep = "WHERE"; querysep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
sprintf(buf, " %s \"%s\" = $%d", querysep, quoteOneName(attname,
tgargs[4 + i * 2], i + 1); tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
strcat(querystr, buf); sprintf(querystr + strlen(querystr), " %s %s = $%d",
querysep, attname, i+1);
querysep = "AND"; querysep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
qkey.keypair[i][RI_KEYPAIR_PK_IDX]); qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
} }
sprintf(buf, " FOR UPDATE OF \"%s\"", strcat(querystr, " FOR UPDATE OF x");
tgargs[RI_FK_RELNAME_ARGNO]);
strcat(querystr, buf);
/* /*
* Prepare, save and remember the new plan. * Prepare, save and remember the new plan.
...@@ -1537,12 +1568,14 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS) ...@@ -1537,12 +1568,14 @@ RI_FKey_restrict_del(PG_FUNCTION_ARGS)
elog(ERROR, "%s referential integrity violation - " elog(ERROR, "%s referential integrity violation - "
"key in %s still referenced from %s", "key in %s still referenced from %s",
tgargs[RI_CONSTRAINT_NAME_ARGNO], tgargs[RI_CONSTRAINT_NAME_ARGNO],
tgargs[RI_PK_RELNAME_ARGNO], RelationGetRelationName(pk_rel),
tgargs[RI_FK_RELNAME_ARGNO]); RelationGetRelationName(fk_rel));
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_del()"); elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_del()");
heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -1627,12 +1660,15 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) ...@@ -1627,12 +1660,15 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the new * Get the relation descriptors of the FK and PK tables and the new
* and old tuple. * and old tuple.
*
* fk_rel is opened in RowShareLock mode since that's what our
* eventual SELECT FOR UPDATE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowShareLock);
fk_owner = RelationGetForm(fk_rel)->relowner;
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
new_row = trigdata->tg_newtuple; new_row = trigdata->tg_newtuple;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
fk_owner = RelationGetForm(fk_rel)->relowner;
switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
{ {
...@@ -1659,7 +1695,7 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) ...@@ -1659,7 +1695,7 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
* No check - MATCH FULL means there cannot be any * No check - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -1669,14 +1705,16 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) ...@@ -1669,14 +1705,16 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
*/ */
break; break;
} }
heap_close(fk_rel, NoLock);
/* /*
* No need to check anything if old and new keys are equal * No need to check anything if old and new keys are equal
*/ */
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey, if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
RI_KEYPAIR_PK_IDX)) RI_KEYPAIR_PK_IDX))
{
heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
}
if (SPI_connect() != SPI_OK_CONNECT) if (SPI_connect() != SPI_OK_CONNECT)
elog(WARNING, "SPI_connect() failed in RI_FKey_restrict_upd()"); elog(WARNING, "SPI_connect() failed in RI_FKey_restrict_upd()");
...@@ -1687,9 +1725,11 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) ...@@ -1687,9 +1725,11 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
*/ */
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
/* ---------- /* ----------
...@@ -1701,21 +1741,20 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) ...@@ -1701,21 +1741,20 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "SELECT 1 FROM ONLY \"%s\"", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "SELECT 1 FROM ONLY %s x", fkrelname);
querysep = "WHERE"; querysep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
sprintf(buf, " %s \"%s\" = $%d", querysep, quoteOneName(attname,
tgargs[4 + i * 2], i + 1); tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
strcat(querystr, buf); sprintf(querystr + strlen(querystr), " %s %s = $%d",
querysep, attname, i+1);
querysep = "AND"; querysep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
qkey.keypair[i][RI_KEYPAIR_PK_IDX]); qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
} }
sprintf(buf, " FOR UPDATE OF \"%s\"", strcat(querystr, " FOR UPDATE OF x");
tgargs[RI_FK_RELNAME_ARGNO]);
strcat(querystr, buf);
/* /*
* Prepare, save and remember the new plan. * Prepare, save and remember the new plan.
...@@ -1759,12 +1798,14 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS) ...@@ -1759,12 +1798,14 @@ RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
elog(ERROR, "%s referential integrity violation - " elog(ERROR, "%s referential integrity violation - "
"key in %s still referenced from %s", "key in %s still referenced from %s",
tgargs[RI_CONSTRAINT_NAME_ARGNO], tgargs[RI_CONSTRAINT_NAME_ARGNO],
tgargs[RI_PK_RELNAME_ARGNO], RelationGetRelationName(pk_rel),
tgargs[RI_FK_RELNAME_ARGNO]); RelationGetRelationName(fk_rel));
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_upd()"); elog(WARNING, "SPI_finish() failed in RI_FKey_restrict_upd()");
heap_close(fk_rel, RowShareLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -1841,11 +1882,14 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) ...@@ -1841,11 +1882,14 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the old * Get the relation descriptors of the FK and PK tables and the old
* tuple. * tuple.
*
* fk_rel is opened in RowExclusiveLock mode since that's what our
* eventual UPDATE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
fk_owner = RelationGetForm(fk_rel)->relowner;
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
fk_owner = RelationGetForm(fk_rel)->relowner;
switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
{ {
...@@ -1872,7 +1916,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) ...@@ -1872,7 +1916,7 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
* No update - MATCH FULL means there cannot be any * No update - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -1882,7 +1926,6 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) ...@@ -1882,7 +1926,6 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
*/ */
break; break;
} }
heap_close(fk_rel, NoLock);
if (SPI_connect() != SPI_OK_CONNECT) if (SPI_connect() != SPI_OK_CONNECT)
elog(WARNING, "SPI_connect() failed in RI_FKey_setnull_del()"); elog(WARNING, "SPI_connect() failed in RI_FKey_setnull_del()");
...@@ -1893,11 +1936,13 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) ...@@ -1893,11 +1936,13 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
*/ */
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL) if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS * 2];
char qualstr[8192]; char qualstr[(MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char *qualsep; char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
const char *qualsep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
/* ---------- /* ----------
...@@ -1910,19 +1955,19 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) ...@@ -1910,19 +1955,19 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "UPDATE ONLY \"%s\" SET", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "UPDATE ONLY %s SET", fkrelname);
qualstr[0] = '\0'; qualstr[0] = '\0';
querysep = ""; querysep = "";
qualsep = "WHERE"; qualsep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
sprintf(buf, "%s \"%s\" = NULL", querysep, quoteOneName(attname,
tgargs[4 + i * 2]); tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
strcat(querystr, buf); sprintf(querystr + strlen(querystr), "%s %s = NULL",
sprintf(buf, " %s \"%s\" = $%d", qualsep, querysep, attname);
tgargs[4 + i * 2], i + 1); sprintf(qualstr + strlen(qualstr), " %s %s = $%d",
strcat(qualstr, buf); qualsep, attname, i+1);
querysep = ","; querysep = ",";
qualsep = "AND"; qualsep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
...@@ -1969,6 +2014,8 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS) ...@@ -1969,6 +2014,8 @@ RI_FKey_setnull_del(PG_FUNCTION_ARGS)
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_del()"); elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_del()");
heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -2048,13 +2095,16 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) ...@@ -2048,13 +2095,16 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the old * Get the relation descriptors of the FK and PK tables and the old
* tuple. * tuple.
*
* fk_rel is opened in RowExclusiveLock mode since that's what our
* eventual UPDATE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
fk_owner = RelationGetForm(fk_rel)->relowner;
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
new_row = trigdata->tg_newtuple; new_row = trigdata->tg_newtuple;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
match_type = ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]); match_type = ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]);
fk_owner = RelationGetForm(fk_rel)->relowner;
switch (match_type) switch (match_type)
{ {
...@@ -2081,7 +2131,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) ...@@ -2081,7 +2131,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
* No update - MATCH FULL means there cannot be any * No update - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -2091,15 +2141,16 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) ...@@ -2091,15 +2141,16 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
*/ */
break; break;
} }
heap_close(fk_rel, NoLock);
/* /*
* No need to do anything if old and new keys are equal * No need to do anything if old and new keys are equal
*/ */
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey, if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
RI_KEYPAIR_PK_IDX)) RI_KEYPAIR_PK_IDX))
{
heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
}
if (SPI_connect() != SPI_OK_CONNECT) if (SPI_connect() != SPI_OK_CONNECT)
elog(WARNING, "SPI_connect() failed in RI_FKey_setnull_upd()"); elog(WARNING, "SPI_connect() failed in RI_FKey_setnull_upd()");
...@@ -2129,11 +2180,13 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) ...@@ -2129,11 +2180,13 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
if (!use_cached_query || if (!use_cached_query ||
(qplan = ri_FetchPreparedPlan(&qkey)) == NULL) (qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS * 2];
char qualstr[8192]; char qualstr[(MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char *qualsep; char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
const char *qualsep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
/* ---------- /* ----------
...@@ -2146,13 +2199,15 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) ...@@ -2146,13 +2199,15 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "UPDATE ONLY \"%s\" SET", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "UPDATE ONLY %s SET", fkrelname);
qualstr[0] = '\0'; qualstr[0] = '\0';
querysep = ""; querysep = "";
qualsep = "WHERE"; qualsep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
quoteOneName(attname,
tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
/* /*
* MATCH <unspecified> - only change columns * MATCH <unspecified> - only change columns
* corresponding to changed columns in pk_rel's key * corresponding to changed columns in pk_rel's key
...@@ -2161,14 +2216,12 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) ...@@ -2161,14 +2216,12 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
!ri_OneKeyEqual(pk_rel, i, old_row, new_row, &qkey, !ri_OneKeyEqual(pk_rel, i, old_row, new_row, &qkey,
RI_KEYPAIR_PK_IDX)) RI_KEYPAIR_PK_IDX))
{ {
sprintf(buf, "%s \"%s\" = NULL", querysep, sprintf(querystr + strlen(querystr), "%s %s = NULL",
tgargs[4 + i * 2]); querysep, attname);
strcat(querystr, buf);
querysep = ","; querysep = ",";
} }
sprintf(buf, " %s \"%s\" = $%d", qualsep, sprintf(qualstr + strlen(qualstr), " %s %s = $%d",
tgargs[4 + i * 2], i + 1); qualsep, attname, i+1);
strcat(qualstr, buf);
qualsep = "AND"; qualsep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
qkey.keypair[i][RI_KEYPAIR_PK_IDX]); qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
...@@ -2222,6 +2275,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS) ...@@ -2222,6 +2275,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_upd()"); elog(WARNING, "SPI_finish() failed in RI_FKey_setnull_upd()");
heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -2298,11 +2353,14 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) ...@@ -2298,11 +2353,14 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the old * Get the relation descriptors of the FK and PK tables and the old
* tuple. * tuple.
*
* fk_rel is opened in RowExclusiveLock mode since that's what our
* eventual UPDATE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
fk_owner = RelationGetForm(fk_rel)->relowner;
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
fk_owner = RelationGetForm(fk_rel)->relowner;
switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO])) switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
{ {
...@@ -2329,7 +2387,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) ...@@ -2329,7 +2387,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
* No update - MATCH FULL means there cannot be any * No update - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -2344,16 +2402,18 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) ...@@ -2344,16 +2402,18 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
elog(WARNING, "SPI_connect() failed in RI_FKey_setdefault_del()"); elog(WARNING, "SPI_connect() failed in RI_FKey_setdefault_del()");
/* /*
* Prepare a plan for the set defalt delete operation. * Prepare a plan for the set default delete operation.
* Unfortunately we need to do it on every invocation because * Unfortunately we need to do it on every invocation because
* the default value could potentially change between calls. * the default value could potentially change between calls.
*/ */
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS * 2];
char qualstr[8192]; char qualstr[(MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char *qualsep; char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
const char *qualsep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
Plan *spi_plan; Plan *spi_plan;
AttrDefault *defval; AttrDefault *defval;
...@@ -2371,19 +2431,19 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) ...@@ -2371,19 +2431,19 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "UPDATE ONLY \"%s\" SET", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "UPDATE ONLY %s SET", fkrelname);
qualstr[0] = '\0'; qualstr[0] = '\0';
querysep = ""; querysep = "";
qualsep = "WHERE"; qualsep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
sprintf(buf, "%s \"%s\" = NULL", querysep, quoteOneName(attname,
tgargs[4 + i * 2]); tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
strcat(querystr, buf); sprintf(querystr + strlen(querystr), "%s %s = NULL",
sprintf(buf, " %s \"%s\" = $%d", qualsep, querysep, attname);
tgargs[4 + i * 2], i + 1); sprintf(qualstr + strlen(qualstr), " %s %s = $%d",
strcat(qualstr, buf); qualsep, attname, i+1);
querysep = ","; querysep = ",";
qualsep = "AND"; qualsep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
...@@ -2437,8 +2497,6 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) ...@@ -2437,8 +2497,6 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
} }
} }
} }
/* fk_rel is no longer needed OK ? */
heap_close(fk_rel, NoLock);
/* /*
* We have a plan now. Build up the arguments for SPI_execp() * We have a plan now. Build up the arguments for SPI_execp()
...@@ -2471,6 +2529,8 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS) ...@@ -2471,6 +2529,8 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_del()"); elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_del()");
heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -2549,12 +2609,15 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) ...@@ -2549,12 +2609,15 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
/* /*
* Get the relation descriptors of the FK and PK tables and the old * Get the relation descriptors of the FK and PK tables and the old
* tuple. * tuple.
*
* fk_rel is opened in RowExclusiveLock mode since that's what our
* eventual UPDATE will get on it.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, RowExclusiveLock);
fk_owner = RelationGetForm(fk_rel)->relowner;
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
new_row = trigdata->tg_newtuple; new_row = trigdata->tg_newtuple;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
fk_owner = RelationGetForm(fk_rel)->relowner;
match_type = ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]); match_type = ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]);
...@@ -2583,7 +2646,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) ...@@ -2583,7 +2646,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
* No update - MATCH FULL means there cannot be any * No update - MATCH FULL means there cannot be any
* reference to old key if it contains NULL * reference to old key if it contains NULL
*/ */
heap_close(fk_rel, NoLock); heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
case RI_KEYS_NONE_NULL: case RI_KEYS_NONE_NULL:
...@@ -2599,22 +2662,27 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) ...@@ -2599,22 +2662,27 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
*/ */
if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey, if (ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
RI_KEYPAIR_PK_IDX)) RI_KEYPAIR_PK_IDX))
{
heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
}
if (SPI_connect() != SPI_OK_CONNECT) if (SPI_connect() != SPI_OK_CONNECT)
elog(WARNING, "SPI_connect() failed in RI_FKey_setdefault_upd()"); elog(WARNING, "SPI_connect() failed in RI_FKey_setdefault_upd()");
/* /*
* Prepare a plan for the set defalt delete operation. * Prepare a plan for the set default delete operation.
* Unfortunately we need to do it on every invocation because * Unfortunately we need to do it on every invocation because
* the default value could potentially change between calls. * the default value could potentially change between calls.
*/ */
{ {
char buf[256]; char querystr[MAX_QUOTED_REL_NAME_LEN + 100 +
char querystr[8192]; (MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS * 2];
char qualstr[8192]; char qualstr[(MAX_QUOTED_NAME_LEN + 32) * RI_MAX_NUMKEYS];
char *querysep; char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char *qualsep; char attname[MAX_QUOTED_NAME_LEN];
const char *querysep;
const char *qualsep;
Oid queryoids[RI_MAX_NUMKEYS]; Oid queryoids[RI_MAX_NUMKEYS];
Plan *spi_plan; Plan *spi_plan;
AttrDefault *defval; AttrDefault *defval;
...@@ -2632,13 +2700,15 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) ...@@ -2632,13 +2700,15 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
* how to compare these two types by '='. * how to compare these two types by '='.
* ---------- * ----------
*/ */
sprintf(querystr, "UPDATE ONLY \"%s\" SET", quoteRelationName(fkrelname, fk_rel);
tgargs[RI_FK_RELNAME_ARGNO]); sprintf(querystr, "UPDATE ONLY %s SET", fkrelname);
qualstr[0] = '\0'; qualstr[0] = '\0';
querysep = ""; querysep = "";
qualsep = "WHERE"; qualsep = "WHERE";
for (i = 0; i < qkey.nkeypairs; i++) for (i = 0; i < qkey.nkeypairs; i++)
{ {
quoteOneName(attname,
tgargs[RI_FIRST_ATTNAME_ARGNO + i * 2 + RI_KEYPAIR_FK_IDX]);
/* /*
* MATCH <unspecified> - only change columns * MATCH <unspecified> - only change columns
* corresponding to changed columns in pk_rel's key * corresponding to changed columns in pk_rel's key
...@@ -2647,14 +2717,12 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) ...@@ -2647,14 +2717,12 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
!ri_OneKeyEqual(pk_rel, i, old_row, !ri_OneKeyEqual(pk_rel, i, old_row,
new_row, &qkey, RI_KEYPAIR_PK_IDX)) new_row, &qkey, RI_KEYPAIR_PK_IDX))
{ {
sprintf(buf, "%s \"%s\" = NULL", querysep, sprintf(querystr + strlen(querystr), "%s %s = NULL",
tgargs[4 + i * 2]); querysep, attname);
strcat(querystr, buf);
querysep = ","; querysep = ",";
} }
sprintf(buf, " %s \"%s\" = $%d", qualsep, sprintf(qualstr + strlen(qualstr), " %s %s = $%d",
tgargs[4 + i * 2], i + 1); qualsep, attname, i+1);
strcat(qualstr, buf);
qualsep = "AND"; qualsep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att, queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
qkey.keypair[i][RI_KEYPAIR_PK_IDX]); qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
...@@ -2713,8 +2781,6 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) ...@@ -2713,8 +2781,6 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
} }
} }
} }
/* fk_rel is no longer needed OK ? */
heap_close(fk_rel, NoLock);
/* /*
* We have a plan now. Build up the arguments for SPI_execp() * We have a plan now. Build up the arguments for SPI_execp()
...@@ -2747,6 +2813,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS) ...@@ -2747,6 +2813,8 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_upd()"); elog(WARNING, "SPI_finish() failed in RI_FKey_setdefault_upd()");
heap_close(fk_rel, RowExclusiveLock);
return PointerGetDatum(NULL); return PointerGetDatum(NULL);
/* /*
...@@ -2805,8 +2873,10 @@ RI_FKey_keyequal_upd(TriggerData *trigdata) ...@@ -2805,8 +2873,10 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
/* /*
* Get the relation descriptors of the FK and PK tables and the new * Get the relation descriptors of the FK and PK tables and the new
* and old tuple. * and old tuple.
*
* Use minimal locking for fk_rel here.
*/ */
fk_rel = kluge_openr(tgargs[RI_FK_RELNAME_ARGNO], NoLock); fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, AccessShareLock);
pk_rel = trigdata->tg_relation; pk_rel = trigdata->tg_relation;
new_row = trigdata->tg_newtuple; new_row = trigdata->tg_newtuple;
old_row = trigdata->tg_trigtuple; old_row = trigdata->tg_trigtuple;
...@@ -2822,7 +2892,8 @@ RI_FKey_keyequal_upd(TriggerData *trigdata) ...@@ -2822,7 +2892,8 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
0, 0,
fk_rel, pk_rel, fk_rel, pk_rel,
tgnargs, tgargs); tgnargs, tgargs);
heap_close(fk_rel, NoLock);
heap_close(fk_rel, AccessShareLock);
/* /*
* Return if key's are equal * Return if key's are equal
...@@ -2855,7 +2926,50 @@ RI_FKey_keyequal_upd(TriggerData *trigdata) ...@@ -2855,7 +2926,50 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
*/ */
/*
* quoteOneName --- safely quote a single SQL name
*
* buffer must be MAX_QUOTED_NAME_LEN long (includes room for \0)
*/
static void
quoteOneName(char *buffer, const char *name)
{
/* Rather than trying to be smart, just always quote it. */
*buffer++ = '"';
while (*name)
{
if (*name == '"')
*buffer++ = '"';
*buffer++ = *name++;
}
*buffer++ = '"';
*buffer = '\0';
}
/*
* quoteRelationName --- safely quote a fully qualified relation name
*
* buffer must be MAX_QUOTED_REL_NAME_LEN long (includes room for \0)
*/
static void
quoteRelationName(char *buffer, Relation rel)
{
HeapTuple tuple;
char *nsname;
tuple = SearchSysCache(NAMESPACEOID,
ObjectIdGetDatum(RelationGetNamespace(rel)),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "Failed to lookup namespace %u of relation %s",
RelationGetNamespace(rel), RelationGetRelationName(rel));
nsname = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname);
quoteOneName(buffer, nsname);
ReleaseSysCache(tuple);
buffer += strlen(buffer);
*buffer++ = '.';
quoteOneName(buffer, RelationGetRelationName(rel));
}
/* ---------- /* ----------
...@@ -2867,11 +2981,11 @@ RI_FKey_keyequal_upd(TriggerData *trigdata) ...@@ -2867,11 +2981,11 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
static int static int
ri_DetermineMatchType(char *str) ri_DetermineMatchType(char *str)
{ {
if (!strcmp(str, "UNSPECIFIED")) if (strcmp(str, "UNSPECIFIED") == 0)
return RI_MATCH_TYPE_UNSPECIFIED; return RI_MATCH_TYPE_UNSPECIFIED;
if (!strcmp(str, "FULL")) if (strcmp(str, "FULL") == 0)
return RI_MATCH_TYPE_FULL; return RI_MATCH_TYPE_FULL;
if (!strcmp(str, "PARTIAL")) if (strcmp(str, "PARTIAL") == 0)
return RI_MATCH_TYPE_PARTIAL; return RI_MATCH_TYPE_PARTIAL;
elog(ERROR, "unrecognized referential integrity MATCH type '%s'", str); elog(ERROR, "unrecognized referential integrity MATCH type '%s'", str);
...@@ -2926,7 +3040,7 @@ ri_BuildQueryKeyFull(RI_QueryKey *key, Oid constr_id, int32 constr_queryno, ...@@ -2926,7 +3040,7 @@ ri_BuildQueryKeyFull(RI_QueryKey *key, Oid constr_id, int32 constr_queryno,
if (fno == SPI_ERROR_NOATTRIBUTE) if (fno == SPI_ERROR_NOATTRIBUTE)
elog(ERROR, "constraint %s: table %s does not have an attribute %s", elog(ERROR, "constraint %s: table %s does not have an attribute %s",
argv[RI_CONSTRAINT_NAME_ARGNO], argv[RI_CONSTRAINT_NAME_ARGNO],
argv[RI_FK_RELNAME_ARGNO], RelationGetRelationName(fk_rel),
argv[j]); argv[j]);
key->keypair[i][RI_KEYPAIR_FK_IDX] = fno; key->keypair[i][RI_KEYPAIR_FK_IDX] = fno;
...@@ -2934,12 +3048,10 @@ ri_BuildQueryKeyFull(RI_QueryKey *key, Oid constr_id, int32 constr_queryno, ...@@ -2934,12 +3048,10 @@ ri_BuildQueryKeyFull(RI_QueryKey *key, Oid constr_id, int32 constr_queryno,
if (fno == SPI_ERROR_NOATTRIBUTE) if (fno == SPI_ERROR_NOATTRIBUTE)
elog(ERROR, "constraint %s: table %s does not have an attribute %s", elog(ERROR, "constraint %s: table %s does not have an attribute %s",
argv[RI_CONSTRAINT_NAME_ARGNO], argv[RI_CONSTRAINT_NAME_ARGNO],
argv[RI_PK_RELNAME_ARGNO], RelationGetRelationName(pk_rel),
argv[j + 1]); argv[j + 1]);
key->keypair[i][RI_KEYPAIR_PK_IDX] = fno; key->keypair[i][RI_KEYPAIR_PK_IDX] = fno;
} }
return;
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: trigger.h,v 1.33 2002/03/29 22:10:34 tgl Exp $ * $Id: trigger.h,v 1.34 2002/04/01 22:36:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -81,6 +81,12 @@ typedef struct TriggerData ...@@ -81,6 +81,12 @@ typedef struct TriggerData
* constrname\0fkrel\0pkrel\0matchtype\0fkatt\0pkatt\0fkatt\0pkatt\0... * constrname\0fkrel\0pkrel\0matchtype\0fkatt\0pkatt\0fkatt\0pkatt\0...
* *
* There are one or more pairs of fkatt/pkatt names. * There are one or more pairs of fkatt/pkatt names.
*
* The relation names are no longer of much use since they are not
* guaranteed unique; they are present only for backwards compatibility.
* Use the tgrelid and tgconstrrelid fields to identify the referenced
* relations, instead. (But note that which is which will depend on which
* trigger you are looking at!)
*/ */
#define RI_CONSTRAINT_NAME_ARGNO 0 #define RI_CONSTRAINT_NAME_ARGNO 0
#define RI_FK_RELNAME_ARGNO 1 #define RI_FK_RELNAME_ARGNO 1
...@@ -127,9 +133,8 @@ extern void ExecARUpdateTriggers(EState *estate, ...@@ -127,9 +133,8 @@ extern void ExecARUpdateTriggers(EState *estate,
HeapTuple newtuple); HeapTuple newtuple);
/* ---------- /*
* Deferred trigger stuff * Deferred trigger stuff
* ----------
*/ */
typedef struct DeferredTriggerStatusData typedef struct DeferredTriggerStatusData
{ {
...@@ -139,14 +144,12 @@ typedef struct DeferredTriggerStatusData ...@@ -139,14 +144,12 @@ typedef struct DeferredTriggerStatusData
typedef struct DeferredTriggerStatusData *DeferredTriggerStatus; typedef struct DeferredTriggerStatusData *DeferredTriggerStatus;
typedef struct DeferredTriggerEventItem typedef struct DeferredTriggerEventItem
{ {
Oid dti_tgoid; Oid dti_tgoid;
int32 dti_state; int32 dti_state;
} DeferredTriggerEventItem; } DeferredTriggerEventItem;
typedef struct DeferredTriggerEventData *DeferredTriggerEvent; typedef struct DeferredTriggerEventData *DeferredTriggerEvent;
typedef struct DeferredTriggerEventData typedef struct DeferredTriggerEventData
...@@ -173,7 +176,6 @@ extern void DeferredTriggerSetState(ConstraintsSetStmt *stmt); ...@@ -173,7 +176,6 @@ extern void DeferredTriggerSetState(ConstraintsSetStmt *stmt);
/* /*
* in utils/adt/ri_triggers.c * in utils/adt/ri_triggers.c
*
*/ */
extern bool RI_FKey_keyequal_upd(TriggerData *trigdata); extern bool RI_FKey_keyequal_upd(TriggerData *trigdata);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: rel.h,v 1.58 2002/03/31 06:26:32 tgl Exp $ * $Id: rel.h,v 1.59 2002/04/01 22:36:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -49,12 +49,14 @@ typedef LockInfoData *LockInfo; ...@@ -49,12 +49,14 @@ typedef LockInfoData *LockInfo;
*/ */
typedef struct Trigger typedef struct Trigger
{ {
Oid tgoid; Oid tgoid; /* OID of trigger (pg_trigger row) */
/* Remaining fields are copied from pg_trigger, see pg_trigger.h */
char *tgname; char *tgname;
Oid tgfoid; Oid tgfoid;
int16 tgtype; int16 tgtype;
bool tgenabled; bool tgenabled;
bool tgisconstraint; bool tgisconstraint;
Oid tgconstrrelid;
bool tgdeferrable; bool tgdeferrable;
bool tginitdeferred; bool tginitdeferred;
int16 tgnargs; int16 tgnargs;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment