00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "postgres.h"
00023
00024 #include "access/htup_details.h"
00025 #include "access/xact.h"
00026 #include "executor/executor.h"
00027 #include "executor/nodeLockRows.h"
00028 #include "storage/bufmgr.h"
00029 #include "utils/rel.h"
00030 #include "utils/tqual.h"
00031
00032
00033
00034
00035
00036
00037 TupleTableSlot *
00038 ExecLockRows(LockRowsState *node)
00039 {
00040 TupleTableSlot *slot;
00041 EState *estate;
00042 PlanState *outerPlan;
00043 bool epq_started;
00044 ListCell *lc;
00045
00046
00047
00048
00049 estate = node->ps.state;
00050 outerPlan = outerPlanState(node);
00051
00052
00053
00054
00055 lnext:
00056 slot = ExecProcNode(outerPlan);
00057
00058 if (TupIsNull(slot))
00059 return NULL;
00060
00061
00062
00063
00064
00065 epq_started = false;
00066 foreach(lc, node->lr_arowMarks)
00067 {
00068 ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
00069 ExecRowMark *erm = aerm->rowmark;
00070 Datum datum;
00071 bool isNull;
00072 HeapTupleData tuple;
00073 Buffer buffer;
00074 HeapUpdateFailureData hufd;
00075 LockTupleMode lockmode;
00076 HTSU_Result test;
00077 HeapTuple copyTuple;
00078
00079
00080 if (node->lr_epqstate.estate != NULL)
00081 EvalPlanQualSetTuple(&node->lr_epqstate, erm->rti, NULL);
00082
00083
00084 if (erm->rti != erm->prti)
00085 {
00086 Oid tableoid;
00087
00088 datum = ExecGetJunkAttribute(slot,
00089 aerm->toidAttNo,
00090 &isNull);
00091
00092 if (isNull)
00093 elog(ERROR, "tableoid is NULL");
00094 tableoid = DatumGetObjectId(datum);
00095
00096 if (tableoid != RelationGetRelid(erm->relation))
00097 {
00098
00099 ItemPointerSetInvalid(&(erm->curCtid));
00100 continue;
00101 }
00102 }
00103
00104
00105 datum = ExecGetJunkAttribute(slot,
00106 aerm->ctidAttNo,
00107 &isNull);
00108
00109 if (isNull)
00110 elog(ERROR, "ctid is NULL");
00111 tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
00112
00113
00114 switch (erm->markType)
00115 {
00116 case ROW_MARK_EXCLUSIVE:
00117 lockmode = LockTupleExclusive;
00118 break;
00119 case ROW_MARK_NOKEYEXCLUSIVE:
00120 lockmode = LockTupleNoKeyExclusive;
00121 break;
00122 case ROW_MARK_SHARE:
00123 lockmode = LockTupleShare;
00124 break;
00125 case ROW_MARK_KEYSHARE:
00126 lockmode = LockTupleKeyShare;
00127 break;
00128 default:
00129 elog(ERROR, "unsupported rowmark type");
00130 lockmode = LockTupleNoKeyExclusive;
00131 break;
00132 }
00133
00134 test = heap_lock_tuple(erm->relation, &tuple,
00135 estate->es_output_cid,
00136 lockmode, erm->noWait, true,
00137 &buffer, &hufd);
00138 ReleaseBuffer(buffer);
00139 switch (test)
00140 {
00141 case HeapTupleSelfUpdated:
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 goto lnext;
00155
00156 case HeapTupleMayBeUpdated:
00157
00158 break;
00159
00160 case HeapTupleUpdated:
00161 if (IsolationUsesXactSnapshot())
00162 ereport(ERROR,
00163 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
00164 errmsg("could not serialize access due to concurrent update")));
00165 if (ItemPointerEquals(&hufd.ctid, &tuple.t_self))
00166 {
00167
00168 goto lnext;
00169 }
00170
00171
00172 copyTuple = EvalPlanQualFetch(estate, erm->relation, lockmode,
00173 &hufd.ctid, hufd.xmax);
00174
00175 if (copyTuple == NULL)
00176 {
00177
00178 goto lnext;
00179 }
00180
00181 tuple.t_self = copyTuple->t_self;
00182
00183
00184
00185
00186
00187 if (!epq_started)
00188 {
00189 EvalPlanQualBegin(&node->lr_epqstate, estate);
00190 epq_started = true;
00191 }
00192
00193
00194 EvalPlanQualSetTuple(&node->lr_epqstate, erm->rti, copyTuple);
00195
00196
00197 break;
00198
00199 default:
00200 elog(ERROR, "unrecognized heap_lock_tuple status: %u",
00201 test);
00202 }
00203
00204
00205 erm->curCtid = tuple.t_self;
00206 }
00207
00208
00209
00210
00211 if (epq_started)
00212 {
00213
00214
00215
00216
00217
00218
00219 foreach(lc, node->lr_arowMarks)
00220 {
00221 ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
00222 ExecRowMark *erm = aerm->rowmark;
00223 HeapTupleData tuple;
00224 Buffer buffer;
00225
00226
00227 if (!ItemPointerIsValid(&(erm->curCtid)))
00228 {
00229 Assert(erm->rti != erm->prti);
00230 continue;
00231 }
00232
00233 if (EvalPlanQualGetTuple(&node->lr_epqstate, erm->rti) != NULL)
00234 continue;
00235
00236
00237 tuple.t_self = erm->curCtid;
00238 if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
00239 false, NULL))
00240 elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
00241
00242
00243 EvalPlanQualSetTuple(&node->lr_epqstate, erm->rti,
00244 heap_copytuple(&tuple));
00245 ReleaseBuffer(buffer);
00246 }
00247
00248
00249
00250
00251
00252 EvalPlanQualSetSlot(&node->lr_epqstate, slot);
00253 EvalPlanQualFetchRowMarks(&node->lr_epqstate);
00254
00255
00256
00257
00258 slot = EvalPlanQualNext(&node->lr_epqstate);
00259 if (TupIsNull(slot))
00260 {
00261
00262 goto lnext;
00263 }
00264 }
00265
00266
00267 return slot;
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277 LockRowsState *
00278 ExecInitLockRows(LockRows *node, EState *estate, int eflags)
00279 {
00280 LockRowsState *lrstate;
00281 Plan *outerPlan = outerPlan(node);
00282 List *epq_arowmarks;
00283 ListCell *lc;
00284
00285
00286 Assert(!(eflags & EXEC_FLAG_MARK));
00287
00288
00289
00290
00291 lrstate = makeNode(LockRowsState);
00292 lrstate->ps.plan = (Plan *) node;
00293 lrstate->ps.state = estate;
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 ExecInitResultTupleSlot(estate, &lrstate->ps);
00305
00306
00307
00308
00309 outerPlanState(lrstate) = ExecInitNode(outerPlan, estate, eflags);
00310
00311
00312
00313
00314
00315 ExecAssignResultTypeFromTL(&lrstate->ps);
00316 lrstate->ps.ps_ProjInfo = NULL;
00317
00318
00319
00320
00321
00322
00323 lrstate->lr_arowMarks = NIL;
00324 epq_arowmarks = NIL;
00325 foreach(lc, node->rowMarks)
00326 {
00327 PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
00328 ExecRowMark *erm;
00329 ExecAuxRowMark *aerm;
00330
00331 Assert(IsA(rc, PlanRowMark));
00332
00333
00334 if (rc->isParent)
00335 continue;
00336
00337
00338 erm = ExecFindRowMark(estate, rc->rti);
00339 aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
00340
00341
00342
00343
00344
00345
00346
00347 if (RowMarkRequiresRowShareLock(erm->markType))
00348 lrstate->lr_arowMarks = lappend(lrstate->lr_arowMarks, aerm);
00349 else
00350 epq_arowmarks = lappend(epq_arowmarks, aerm);
00351 }
00352
00353
00354 EvalPlanQualInit(&lrstate->lr_epqstate, estate,
00355 outerPlan, epq_arowmarks, node->epqParam);
00356
00357 return lrstate;
00358 }
00359
00360
00361
00362
00363
00364
00365
00366
00367 void
00368 ExecEndLockRows(LockRowsState *node)
00369 {
00370 EvalPlanQualEnd(&node->lr_epqstate);
00371 ExecEndNode(outerPlanState(node));
00372 }
00373
00374
00375 void
00376 ExecReScanLockRows(LockRowsState *node)
00377 {
00378
00379
00380
00381
00382 if (node->ps.lefttree->chgParam == NULL)
00383 ExecReScan(node->ps.lefttree);
00384 }