*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.49 2003/04/07 20:30:38 wieck Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.50 2003/04/26 22:21:47 tgl Exp $
*
* ----------
*/
static void ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname,
int tgkind);
+static void *ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
+ RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel,
+ bool cache_plan);
static bool ri_PerformCheck(RI_QueryKey *qkey, void *qplan,
Relation fk_rel, Relation pk_rel,
HeapTuple old_tuple, HeapTuple new_tuple,
fk_rel, pk_rel,
tgnargs, tgargs);
+ if (SPI_connect() != SPI_OK_CONNECT)
+ elog(ERROR, "SPI_connect() failed in RI_FKey_check()");
+
if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
{
char querystr[MAX_QUOTED_REL_NAME_LEN + 100];
snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x FOR UPDATE OF x",
pkrelname);
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, 0, NULL);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, 0, NULL,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* Execute the plan
*/
- if (SPI_connect() != SPI_OK_CONNECT)
- elog(ERROR, "SPI_connect() failed in RI_FKey_check()");
-
ri_PerformCheck(&qkey, qplan,
fk_rel, pk_rel,
NULL, NULL,
* The query string built is
* SELECT 1 FROM ONLY <pktable> WHERE pkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding FK attributes. Thus, SPI_prepare could
+ * corresponding FK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, " FOR UPDATE OF x");
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* The query string built is
* SELECT 1 FROM ONLY <pktable> WHERE pkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding FK attributes. Thus, SPI_prepare could
+ * corresponding FK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, " FOR UPDATE OF x");
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* The query string built is
* SELECT 1 FROM ONLY <fktable> WHERE fkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, " FOR UPDATE OF x");
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* The query string built is
* SELECT 1 FROM ONLY <fktable> WHERE fkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, " FOR UPDATE OF x");
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* The query string built is
* DELETE FROM ONLY <fktable> WHERE fkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
}
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* UPDATE ONLY <fktable> SET fkatt1 = $1 [, ...]
* WHERE fkatt1 = $n [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, qualstr);
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs * 2, queryoids);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs * 2, queryoids,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* The query string built is
* SELECT 1 FROM ONLY <fktable> WHERE fkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, " FOR UPDATE OF x");
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* The query string built is
* SELECT 1 FROM ONLY <fktable> WHERE fkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, " FOR UPDATE OF x");
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]
* WHERE fkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, qualstr);
- /*
- * Prepare, save and remember the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
+ /* Prepare and save the plan */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, true);
}
/*
* UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]
* WHERE fkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
strcat(querystr, qualstr);
/*
- * Prepare the new plan.
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
-
- /*
- * Save and remember the plan if we're building the
+ * Prepare the plan. Save it only if we're building the
* "standard" plan.
*/
- if (use_cached_query)
- {
- qplan = SPI_saveplan(qplan);
- ri_HashPreparedPlan(&qkey, qplan);
- }
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel,
+ use_cached_query);
}
/*
* UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]
* WHERE fkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, qualstr);
- /*
- * Prepare the plan
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
+ /* Prepare the plan, don't save it */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, false);
/*
* Scan the plan's targetlist and replace the NULLs by
* UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]
* WHERE fkatt1 = $1 [AND ...]
* The type id's for the $ parameters are those of the
- * corresponding PK attributes. Thus, SPI_prepare could
+ * corresponding PK attributes. Thus, ri_PlanCheck could
* eventually fail if the parser cannot identify some way
* how to compare these two types by '='.
* ----------
}
strcat(querystr, qualstr);
- /*
- * Prepare the plan
- */
- qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
+ /* Prepare the plan, don't save it */
+ qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
+ &qkey, fk_rel, pk_rel, false);
/*
* Scan the plan's targetlist and replace the NULLs by
}
+/*
+ * Prepare execution plan for a query to enforce an RI restriction
+ *
+ * If cache_plan is true, the plan is saved into our plan hashtable
+ * so that we don't need to plan it again.
+ */
+static void *
+ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
+ RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel,
+ bool cache_plan)
+{
+ void *qplan;
+ Relation query_rel;
+ AclId save_uid;
+
+ /*
+ * The query is always run against the FK table except
+ * when this is an update/insert trigger on the FK table itself -
+ * either RI_PLAN_CHECK_LOOKUPPK or RI_PLAN_CHECK_LOOKUPPK_NOCOLS
+ */
+ if (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK ||
+ qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK_NOCOLS)
+ query_rel = pk_rel;
+ else
+ query_rel = fk_rel;
+
+ /* Switch to proper UID to perform check as */
+ save_uid = GetUserId();
+ SetUserId(RelationGetForm(query_rel)->relowner);
+
+ /* Create the plan */
+ qplan = SPI_prepare(querystr, nargs, argtypes);
+
+ /* Restore UID */
+ SetUserId(save_uid);
+
+ /* Save the plan if requested */
+ if (cache_plan)
+ {
+ qplan = SPI_saveplan(qplan);
+ ri_HashPreparedPlan(qkey, qplan);
+ }
+
+ return qplan;
+}
+
/*
* Perform a query to enforce an RI restriction
*/