diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execMain.c | 43 | ||||
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 33 |
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) |