PostgreSQL Source Code  git master
constraint.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * constraint.c
4  * PostgreSQL CONSTRAINT support code.
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/commands/constraint.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "access/genam.h"
17 #include "access/heapam.h"
18 #include "access/tableam.h"
19 #include "catalog/index.h"
20 #include "commands/trigger.h"
21 #include "executor/executor.h"
22 #include "utils/builtins.h"
23 #include "utils/rel.h"
24 #include "utils/snapmgr.h"
25 
26 
27 /*
28  * unique_key_recheck - trigger function to do a deferred uniqueness check.
29  *
30  * This now also does deferred exclusion-constraint checks, so the name is
31  * somewhat historical.
32  *
33  * This is invoked as an AFTER ROW trigger for both INSERT and UPDATE,
34  * for any rows recorded as potentially violating a deferrable unique
35  * or exclusion constraint.
36  *
37  * This may be an end-of-statement check, a commit-time check, or a
38  * check triggered by a SET CONSTRAINTS command.
39  */
40 Datum
42 {
43  TriggerData *trigdata = castNode(TriggerData, fcinfo->context);
44  const char *funcname = "unique_key_recheck";
45  ItemPointerData checktid;
46  ItemPointerData tmptid;
47  Relation indexRel;
48  IndexInfo *indexInfo;
49  EState *estate;
50  ExprContext *econtext;
51  TupleTableSlot *slot;
53  bool isnull[INDEX_MAX_KEYS];
54 
55  /*
56  * Make sure this is being called as an AFTER ROW trigger. Note:
57  * translatable error strings are shared with ri_triggers.c, so resist the
58  * temptation to fold the function name into them.
59  */
60  if (!CALLED_AS_TRIGGER(fcinfo))
61  ereport(ERROR,
62  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
63  errmsg("function \"%s\" was not called by trigger manager",
64  funcname)));
65 
66  if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
67  !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
68  ereport(ERROR,
69  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
70  errmsg("function \"%s\" must be fired AFTER ROW",
71  funcname)));
72 
73  /*
74  * Get the new data that was inserted/updated.
75  */
76  if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
77  checktid = trigdata->tg_trigslot->tts_tid;
78  else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
79  checktid = trigdata->tg_newslot->tts_tid;
80  else
81  {
82  ereport(ERROR,
83  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
84  errmsg("function \"%s\" must be fired for INSERT or UPDATE",
85  funcname)));
86  ItemPointerSetInvalid(&checktid); /* keep compiler quiet */
87  }
88 
89  slot = table_slot_create(trigdata->tg_relation, NULL);
90 
91  /*
92  * If the row pointed at by checktid is now dead (ie, inserted and then
93  * deleted within our transaction), we can skip the check. However, we
94  * have to be careful, because this trigger gets queued only in response
95  * to index insertions; which means it does not get queued e.g. for HOT
96  * updates. The row we are called for might now be dead, but have a live
97  * HOT child, in which case we still need to make the check ---
98  * effectively, we're applying the check against the live child row,
99  * although we can use the values from this row since by definition all
100  * columns of interest to us are the same.
101  *
102  * This might look like just an optimization, because the index AM will
103  * make this identical test before throwing an error. But it's actually
104  * needed for correctness, because the index AM will also throw an error
105  * if it doesn't find the index entry for the row. If the row's dead then
106  * it's possible the index entry has also been marked dead, and even
107  * removed.
108  */
109  tmptid = checktid;
110  {
112  bool call_again = false;
113 
114  if (!table_index_fetch_tuple(scan, &tmptid, SnapshotSelf, slot,
115  &call_again, NULL))
116  {
117  /*
118  * All rows referenced by the index entry are dead, so skip the
119  * check.
120  */
122  table_index_fetch_end(scan);
123  return PointerGetDatum(NULL);
124  }
125  table_index_fetch_end(scan);
126  }
127 
128  /*
129  * Open the index, acquiring a RowExclusiveLock, just as if we were going
130  * to update it. (This protects against possible changes of the index
131  * schema, not against concurrent updates.)
132  */
133  indexRel = index_open(trigdata->tg_trigger->tgconstrindid,
135  indexInfo = BuildIndexInfo(indexRel);
136 
137  /*
138  * Typically the index won't have expressions, but if it does we need an
139  * EState to evaluate them. We need it for exclusion constraints too,
140  * even if they are just on simple columns.
141  */
142  if (indexInfo->ii_Expressions != NIL ||
143  indexInfo->ii_ExclusionOps != NULL)
144  {
145  estate = CreateExecutorState();
146  econtext = GetPerTupleExprContext(estate);
147  econtext->ecxt_scantuple = slot;
148  }
149  else
150  estate = NULL;
151 
152  /*
153  * Form the index values and isnull flags for the index entry that we need
154  * to check.
155  *
156  * Note: if the index uses functions that are not as immutable as they are
157  * supposed to be, this could produce an index tuple different from the
158  * original. The index AM can catch such errors by verifying that it
159  * finds a matching index entry with the tuple's TID. For exclusion
160  * constraints we check this in check_exclusion_constraint().
161  */
162  FormIndexDatum(indexInfo, slot, estate, values, isnull);
163 
164  /*
165  * Now do the appropriate check.
166  */
167  if (indexInfo->ii_ExclusionOps == NULL)
168  {
169  /*
170  * Note: this is not a real insert; it is a check that the index entry
171  * that has already been inserted is unique. Passing the tuple's tid
172  * (i.e. unmodified by table_index_fetch_tuple()) is correct even if
173  * the row is now dead, because that is the TID the index will know
174  * about.
175  */
176  index_insert(indexRel, values, isnull, &checktid,
178  indexInfo);
179  }
180  else
181  {
182  /*
183  * For exclusion constraints we just do the normal check, but now it's
184  * okay to throw error. In the HOT-update case, we must use the live
185  * HOT child's TID here, else check_exclusion_constraint will think
186  * the child is a conflict.
187  */
188  check_exclusion_constraint(trigdata->tg_relation, indexRel, indexInfo,
189  &tmptid, values, isnull,
190  estate, false);
191  }
192 
193  /*
194  * If that worked, then this index entry is unique or non-excluded, and we
195  * are done.
196  */
197  if (estate != NULL)
198  FreeExecutorState(estate);
199 
201 
202  index_close(indexRel, RowExclusiveLock);
203 
204  return PointerGetDatum(NULL);
205 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:77
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2567
#define NIL
Definition: pg_list.h:65
TupleTableSlot * tg_trigslot
Definition: trigger.h:38
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
#define PointerGetDatum(X)
Definition: postgres.h:556
static IndexFetchTableData * table_index_fetch_begin(Relation rel)
Definition: tableam.h:934
int errcode(int sqlerrcode)
Definition: elog.c:608
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2285
Datum unique_key_recheck(PG_FUNCTION_ARGS)
Definition: constraint.c:41
#define TRIGGER_FIRED_AFTER(event)
Definition: trigger.h:137
void FreeExecutorState(EState *estate)
Definition: execUtils.c:190
#define GetPerTupleExprContext(estate)
Definition: executor.h:501
#define ERROR
Definition: elog.h:43
#define SnapshotSelf
Definition: snapmgr.h:68
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
#define RowExclusiveLock
Definition: lockdefs.h:38
TupleTableSlot * tg_newslot
Definition: trigger.h:39
#define ereport(elevel, rest)
Definition: elog.h:141
EState * CreateExecutorState(void)
Definition: execUtils.c:88
uintptr_t Datum
Definition: postgres.h:367
static bool table_index_fetch_tuple(struct IndexFetchTableData *scan, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, bool *call_again, bool *all_dead)
Definition: tableam.h:981
Trigger * tg_trigger
Definition: trigger.h:37
List * ii_Expressions
Definition: execnodes.h:159
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:25
TriggerEvent tg_event
Definition: trigger.h:33
Oid tgconstrindid
Definition: reltrigger.h:33
#define INDEX_MAX_KEYS
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:223
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define TRIGGER_FIRED_BY_INSERT(event)
Definition: trigger.h:116
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
Oid * ii_ExclusionOps
Definition: execnodes.h:163
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188
void check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, EState *estate, bool newIndex)
Definition: execIndexing.c:866
#define TRIGGER_FIRED_FOR_ROW(event)
Definition: trigger.h:128
static void table_index_fetch_end(struct IndexFetchTableData *scan)
Definition: tableam.h:953
ItemPointerData tts_tid
Definition: tuptable.h:130
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:122
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:126
bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, IndexUniqueCheck checkUnique, IndexInfo *indexInfo)
Definition: indexam.c:170
Relation tg_relation
Definition: trigger.h:34