* ExecRelCheck --- check that tuple meets constraints for result relation * * Returns NULL if OK, else name of failed check constraint */
| 2882 | * Returns NULL if OK, else name of failed check constraint |
| 2883 | */ |
| 2884 | static const char * |
| 2885 | ExecRelCheck(ResultRelInfo *resultRelInfo, |
| 2886 | TupleTableSlot *slot, EState *estate) |
| 2887 | { |
| 2888 | Relation rel = resultRelInfo->ri_RelationDesc; |
| 2889 | int ncheck = rel->rd_att->constr->num_check; |
| 2890 | ConstrCheck *check = rel->rd_att->constr->check; |
| 2891 | ExprContext *econtext; |
| 2892 | MemoryContext oldContext; |
| 2893 | int i; |
| 2894 | |
| 2895 | /* |
| 2896 | * CheckConstraintFetch let this pass with only a warning, but now we |
| 2897 | * should fail rather than possibly failing to enforce an important |
| 2898 | * constraint. |
| 2899 | */ |
| 2900 | if (ncheck != rel->rd_rel->relchecks) |
| 2901 | elog(ERROR, "%d pg_constraint record(s) missing for relation \"%s\"", |
| 2902 | rel->rd_rel->relchecks - ncheck, RelationGetRelationName(rel)); |
| 2903 | |
| 2904 | /* |
| 2905 | * If first time through for this result relation, build expression |
| 2906 | * nodetrees for rel's constraint expressions. Keep them in the per-query |
| 2907 | * memory context so they'll survive throughout the query. |
| 2908 | */ |
| 2909 | if (resultRelInfo->ri_ConstraintExprs == NULL) |
| 2910 | { |
| 2911 | oldContext = MemoryContextSwitchTo(estate->es_query_cxt); |
| 2912 | resultRelInfo->ri_ConstraintExprs = |
| 2913 | (ExprState **) palloc(ncheck * sizeof(ExprState *)); |
| 2914 | for (i = 0; i < ncheck; i++) |
| 2915 | { |
| 2916 | Expr *checkconstr; |
| 2917 | |
| 2918 | checkconstr = stringToNode(check[i].ccbin); |
| 2919 | resultRelInfo->ri_ConstraintExprs[i] = |
| 2920 | ExecPrepareExpr(checkconstr, estate); |
| 2921 | } |
| 2922 | MemoryContextSwitchTo(oldContext); |
| 2923 | } |
| 2924 | |
| 2925 | /* |
| 2926 | * We will use the EState's per-tuple context for evaluating constraint |
| 2927 | * expressions (creating it if it's not already there). |
| 2928 | */ |
| 2929 | econtext = GetPerTupleExprContext(estate); |
| 2930 | |
| 2931 | /* Arrange for econtext's scan tuple to be the tuple under test */ |
| 2932 | econtext->ecxt_scantuple = slot; |
| 2933 | |
| 2934 | /* And evaluate the constraints */ |
| 2935 | for (i = 0; i < ncheck; i++) |
| 2936 | { |
| 2937 | ExprState *checkconstr = resultRelInfo->ri_ConstraintExprs[i]; |
| 2938 | |
| 2939 | /* |
| 2940 | * NOTE: SQL specifies that a NULL result from a constraint expression |
| 2941 | * is not to be treated as a failure. Therefore, use ExecCheck not |
no test coverage detected