mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
WITH CHECK OPTION support for auto-updatable VIEWs
For simple views which are automatically updatable, this patch allows the user to specify what level of checking should be done on records being inserted or updated. For 'LOCAL CHECK', new tuples are validated against the conditionals of the view they are being inserted into, while for 'CASCADED CHECK' the new tuples are validated against the conditionals for all views involved (from the top down). This option is part of the SQL specification. Dean Rasheed, reviewed by Pavel Stehule
This commit is contained in:
@ -1623,6 +1623,49 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecWithCheckOptions -- check that tuple satisfies any WITH CHECK OPTIONs
|
||||
*/
|
||||
void
|
||||
ExecWithCheckOptions(ResultRelInfo *resultRelInfo,
|
||||
TupleTableSlot *slot, EState *estate)
|
||||
{
|
||||
ExprContext *econtext;
|
||||
ListCell *l1, *l2;
|
||||
|
||||
/*
|
||||
* We will use the EState's per-tuple context for evaluating constraint
|
||||
* expressions (creating it if it's not already there).
|
||||
*/
|
||||
econtext = GetPerTupleExprContext(estate);
|
||||
|
||||
/* Arrange for econtext's scan tuple to be the tuple under test */
|
||||
econtext->ecxt_scantuple = slot;
|
||||
|
||||
/* Check each of the constraints */
|
||||
forboth(l1, resultRelInfo->ri_WithCheckOptions,
|
||||
l2, resultRelInfo->ri_WithCheckOptionExprs)
|
||||
{
|
||||
WithCheckOption *wco = (WithCheckOption *) lfirst(l1);
|
||||
ExprState *wcoExpr = (ExprState *) lfirst(l2);
|
||||
|
||||
/*
|
||||
* WITH CHECK OPTION checks are intended to ensure that the new tuple
|
||||
* is visible in the view. If the view's qual evaluates to NULL, then
|
||||
* the new tuple won't be included in the view. Therefore we need to
|
||||
* tell ExecQual to return FALSE for NULL (the opposite of what we do
|
||||
* above for CHECK constraints).
|
||||
*/
|
||||
if (!ExecQual((List *) wcoExpr, econtext, false))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WITH_CHECK_OPTION_VIOLATION),
|
||||
errmsg("new row violates WITH CHECK OPTION for view \"%s\"",
|
||||
wco->viewname),
|
||||
errdetail("Failing row contains %s.",
|
||||
ExecBuildSlotValueDescription(slot, 64))));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecBuildSlotValueDescription -- construct a string representing a tuple
|
||||
*
|
||||
|
@ -281,6 +281,10 @@ ExecInsert(TupleTableSlot *slot,
|
||||
|
||||
list_free(recheckIndexes);
|
||||
|
||||
/* Check any WITH CHECK OPTION constraints */
|
||||
if (resultRelInfo->ri_WithCheckOptions != NIL)
|
||||
ExecWithCheckOptions(resultRelInfo, slot, estate);
|
||||
|
||||
/* Process RETURNING if present */
|
||||
if (resultRelInfo->ri_projectReturning)
|
||||
return ExecProcessReturning(resultRelInfo->ri_projectReturning,
|
||||
@ -777,6 +781,10 @@ lreplace:;
|
||||
|
||||
list_free(recheckIndexes);
|
||||
|
||||
/* Check any WITH CHECK OPTION constraints */
|
||||
if (resultRelInfo->ri_WithCheckOptions != NIL)
|
||||
ExecWithCheckOptions(resultRelInfo, slot, estate);
|
||||
|
||||
/* Process RETURNING if present */
|
||||
if (resultRelInfo->ri_projectReturning)
|
||||
return ExecProcessReturning(resultRelInfo->ri_projectReturning,
|
||||
@ -1129,6 +1137,31 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
||||
|
||||
estate->es_result_relation_info = saved_resultRelInfo;
|
||||
|
||||
/*
|
||||
* Initialize any WITH CHECK OPTION constraints if needed.
|
||||
*/
|
||||
resultRelInfo = mtstate->resultRelInfo;
|
||||
i = 0;
|
||||
foreach(l, node->withCheckOptionLists)
|
||||
{
|
||||
List *wcoList = (List *) lfirst(l);
|
||||
List *wcoExprs = NIL;
|
||||
ListCell *ll;
|
||||
|
||||
foreach(ll, wcoList)
|
||||
{
|
||||
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
|
||||
ExprState *wcoExpr = ExecInitExpr((Expr *) wco->qual,
|
||||
mtstate->mt_plans[i]);
|
||||
wcoExprs = lappend(wcoExprs, wcoExpr);
|
||||
}
|
||||
|
||||
resultRelInfo->ri_WithCheckOptions = wcoList;
|
||||
resultRelInfo->ri_WithCheckOptionExprs = wcoExprs;
|
||||
resultRelInfo++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize RETURNING projections if needed.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user