aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-06-18 19:37:23 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2012-06-18 19:37:23 -0400
commite8c9fd5fdf768323911f7088e8287f63b513c3c6 (patch)
tree381453098ccf289a6aa30934ddafd20ed432439e /src
parent03a5ba24b096a9acbbc9682adc0a27d1db31c570 (diff)
downloadpostgresql-e8c9fd5fdf768323911f7088e8287f63b513c3c6.tar.gz
postgresql-e8c9fd5fdf768323911f7088e8287f63b513c3c6.zip
Allow ON UPDATE/DELETE SET DEFAULT plans to be cached.
Once upon a time, somebody was worried that cached RI plans wouldn't get remade with new default values after ALTER TABLE ... SET DEFAULT, so they didn't allow caching of plans for ON UPDATE/DELETE SET DEFAULT actions. That time is long gone, though (and even at the time I doubt this was the greatest hazard posed by ALTER TABLE...). So allow these triggers to cache their plans just like the others. The cache_plan argument to ri_PlanCheck is now vestigial, since there are no callers that don't pass "true"; but I left it alone in case there is any future need for it.
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/ri_triggers.c24
-rw-r--r--src/test/regress/expected/foreign_key.out36
-rw-r--r--src/test/regress/sql/foreign_key.sql17
3 files changed, 65 insertions, 12 deletions
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index cd1bb262a35..5b439aab6fb 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -2155,12 +2155,12 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
elog(ERROR, "SPI_connect failed");
/*
- * Prepare a plan for the set default delete operation.
- * Unfortunately we need to do it on every invocation because the
- * default value could potentially change between calls.
+ * Fetch or prepare a saved plan for the set default delete
+ * operation
*/
ri_BuildQueryKey(&qkey, &riinfo, RI_PLAN_SETDEFAULT_DEL_DOUPDATE);
+ if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{
StringInfoData querybuf;
StringInfoData qualbuf;
@@ -2207,9 +2207,9 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
}
appendStringInfoString(&querybuf, qualbuf.data);
- /* Prepare the plan, don't save it */
+ /* Prepare and save the plan */
qplan = ri_PlanCheck(querybuf.data, riinfo.nkeys, queryoids,
- &qkey, fk_rel, pk_rel, false);
+ &qkey, fk_rel, pk_rel, true);
}
/*
@@ -2239,7 +2239,7 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
return PointerGetDatum(NULL);
/*
- * Handle MATCH PARTIAL set null delete.
+ * Handle MATCH PARTIAL set default delete.
*/
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
@@ -2348,12 +2348,12 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
elog(ERROR, "SPI_connect failed");
/*
- * Prepare a plan for the set default delete operation.
- * Unfortunately we need to do it on every invocation because the
- * default value could potentially change between calls.
+ * Fetch or prepare a saved plan for the set default update
+ * operation
*/
ri_BuildQueryKey(&qkey, &riinfo, RI_PLAN_SETDEFAULT_UPD_DOUPDATE);
+ if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{
StringInfoData querybuf;
StringInfoData qualbuf;
@@ -2400,9 +2400,9 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
}
appendStringInfoString(&querybuf, qualbuf.data);
- /* Prepare the plan, don't save it */
+ /* Prepare and save the plan */
qplan = ri_PlanCheck(querybuf.data, riinfo.nkeys, queryoids,
- &qkey, fk_rel, pk_rel, false);
+ &qkey, fk_rel, pk_rel, true);
}
/*
@@ -2432,7 +2432,7 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
return PointerGetDatum(NULL);
/*
- * Handle MATCH PARTIAL set null delete.
+ * Handle MATCH PARTIAL set default update.
*/
case FKCONSTR_MATCH_PARTIAL:
ereport(ERROR,
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index 305dfe20d47..a63a89f40bb 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -1319,3 +1319,39 @@ begin;
(2 rows)
commit;
+--
+-- Test that SET DEFAULT actions recognize updates to default values
+--
+create temp table defp (f1 int primary key);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "defp_pkey" for table "defp"
+create temp table defc (f1 int default 0
+ references defp on delete set default);
+insert into defp values (0), (1), (2);
+insert into defc values (2);
+select * from defc;
+ f1
+----
+ 2
+(1 row)
+
+delete from defp where f1 = 2;
+select * from defc;
+ f1
+----
+ 0
+(1 row)
+
+delete from defp where f1 = 0; -- fail
+ERROR: update or delete on table "defp" violates foreign key constraint "defc_f1_fkey" on table "defc"
+DETAIL: Key (f1)=(0) is still referenced from table "defc".
+alter table defc alter column f1 set default 1;
+delete from defp where f1 = 0;
+select * from defc;
+ f1
+----
+ 1
+(1 row)
+
+delete from defp where f1 = 1; -- fail
+ERROR: update or delete on table "defp" violates foreign key constraint "defc_f1_fkey" on table "defc"
+DETAIL: Key (f1)=(1) is still referenced from table "defc".
diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql
index 874d9f7a331..43703d234e7 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -943,3 +943,20 @@ begin;
update selfref set a = 456 where a = 123;
select a, b from selfref;
commit;
+
+--
+-- Test that SET DEFAULT actions recognize updates to default values
+--
+create temp table defp (f1 int primary key);
+create temp table defc (f1 int default 0
+ references defp on delete set default);
+insert into defp values (0), (1), (2);
+insert into defc values (2);
+select * from defc;
+delete from defp where f1 = 2;
+select * from defc;
+delete from defp where f1 = 0; -- fail
+alter table defc alter column f1 set default 1;
+delete from defp where f1 = 0;
+select * from defc;
+delete from defp where f1 = 1; -- fail