Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres.h"
00015
00016 #include "catalog/index.h"
00017 #include "commands/trigger.h"
00018 #include "executor/executor.h"
00019 #include "utils/builtins.h"
00020 #include "utils/rel.h"
00021 #include "utils/tqual.h"
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 Datum
00038 unique_key_recheck(PG_FUNCTION_ARGS)
00039 {
00040 TriggerData *trigdata = (TriggerData *) fcinfo->context;
00041 const char *funcname = "unique_key_recheck";
00042 HeapTuple new_row;
00043 ItemPointerData tmptid;
00044 Relation indexRel;
00045 IndexInfo *indexInfo;
00046 EState *estate;
00047 ExprContext *econtext;
00048 TupleTableSlot *slot;
00049 Datum values[INDEX_MAX_KEYS];
00050 bool isnull[INDEX_MAX_KEYS];
00051
00052
00053
00054
00055
00056
00057 if (!CALLED_AS_TRIGGER(fcinfo))
00058 ereport(ERROR,
00059 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
00060 errmsg("function \"%s\" was not called by trigger manager",
00061 funcname)));
00062
00063 if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
00064 !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
00065 ereport(ERROR,
00066 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
00067 errmsg("function \"%s\" must be fired AFTER ROW",
00068 funcname)));
00069
00070
00071
00072
00073 if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
00074 new_row = trigdata->tg_trigtuple;
00075 else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
00076 new_row = trigdata->tg_newtuple;
00077 else
00078 {
00079 ereport(ERROR,
00080 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
00081 errmsg("function \"%s\" must be fired for INSERT or UPDATE",
00082 funcname)));
00083 new_row = NULL;
00084 }
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 tmptid = new_row->t_self;
00104 if (!heap_hot_search(&tmptid, trigdata->tg_relation, SnapshotSelf, NULL))
00105 {
00106
00107
00108
00109 return PointerGetDatum(NULL);
00110 }
00111
00112
00113
00114
00115
00116
00117 indexRel = index_open(trigdata->tg_trigger->tgconstrindid,
00118 RowExclusiveLock);
00119 indexInfo = BuildIndexInfo(indexRel);
00120
00121
00122
00123
00124 slot = MakeSingleTupleTableSlot(RelationGetDescr(trigdata->tg_relation));
00125
00126 ExecStoreTuple(new_row, slot, InvalidBuffer, false);
00127
00128
00129
00130
00131
00132
00133 if (indexInfo->ii_Expressions != NIL ||
00134 indexInfo->ii_ExclusionOps != NULL)
00135 {
00136 estate = CreateExecutorState();
00137 econtext = GetPerTupleExprContext(estate);
00138 econtext->ecxt_scantuple = slot;
00139 }
00140 else
00141 estate = NULL;
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 FormIndexDatum(indexInfo, slot, estate, values, isnull);
00154
00155
00156
00157
00158 if (indexInfo->ii_ExclusionOps == NULL)
00159 {
00160
00161
00162
00163
00164 index_insert(indexRel, values, isnull, &(new_row->t_self),
00165 trigdata->tg_relation, UNIQUE_CHECK_EXISTING);
00166 }
00167 else
00168 {
00169
00170
00171
00172
00173 check_exclusion_constraint(trigdata->tg_relation, indexRel, indexInfo,
00174 &(new_row->t_self), values, isnull,
00175 estate, false, false);
00176 }
00177
00178
00179
00180
00181
00182 if (estate != NULL)
00183 FreeExecutorState(estate);
00184
00185 ExecDropSingleTupleTableSlot(slot);
00186
00187 index_close(indexRel, RowExclusiveLock);
00188
00189 return PointerGetDatum(NULL);
00190 }