aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c43
-rw-r--r--src/backend/executor/nodeModifyTable.c33
2 files changed, 76 insertions, 0 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 4d7345da577..038f064931e 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1624,6 +1624,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
*
* This is intentionally very similar to BuildIndexValueDescription, but
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 8fe5f1d427a..15f5dccb82a 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -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,
@@ -1130,6 +1138,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.
*/
if (node->returningLists)