00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "postgres.h"
00026
00027 #include "access/sysattr.h"
00028 #include "catalog/pg_type.h"
00029 #include "executor/execdebug.h"
00030 #include "executor/nodeTidscan.h"
00031 #include "optimizer/clauses.h"
00032 #include "storage/bufmgr.h"
00033 #include "utils/array.h"
00034 #include "utils/rel.h"
00035
00036
00037 #define IsCTIDVar(node) \
00038 ((node) != NULL && \
00039 IsA((node), Var) && \
00040 ((Var *) (node))->varattno == SelfItemPointerAttributeNumber && \
00041 ((Var *) (node))->varlevelsup == 0)
00042
00043 static void TidListCreate(TidScanState *tidstate);
00044 static int itemptr_comparator(const void *a, const void *b);
00045 static TupleTableSlot *TidNext(TidScanState *node);
00046
00047
00048
00049
00050
00051
00052
00053
00054 static void
00055 TidListCreate(TidScanState *tidstate)
00056 {
00057 List *evalList = tidstate->tss_tidquals;
00058 ExprContext *econtext = tidstate->ss.ps.ps_ExprContext;
00059 BlockNumber nblocks;
00060 ItemPointerData *tidList;
00061 int numAllocTids;
00062 int numTids;
00063 ListCell *l;
00064
00065
00066
00067
00068
00069
00070
00071 nblocks = RelationGetNumberOfBlocks(tidstate->ss.ss_currentRelation);
00072
00073
00074
00075
00076
00077
00078 numAllocTids = list_length(evalList);
00079 tidList = (ItemPointerData *)
00080 palloc(numAllocTids * sizeof(ItemPointerData));
00081 numTids = 0;
00082 tidstate->tss_isCurrentOf = false;
00083
00084 foreach(l, evalList)
00085 {
00086 ExprState *exstate = (ExprState *) lfirst(l);
00087 Expr *expr = exstate->expr;
00088 ItemPointer itemptr;
00089 bool isNull;
00090
00091 if (is_opclause(expr))
00092 {
00093 FuncExprState *fexstate = (FuncExprState *) exstate;
00094 Node *arg1;
00095 Node *arg2;
00096
00097 arg1 = get_leftop(expr);
00098 arg2 = get_rightop(expr);
00099 if (IsCTIDVar(arg1))
00100 exstate = (ExprState *) lsecond(fexstate->args);
00101 else if (IsCTIDVar(arg2))
00102 exstate = (ExprState *) linitial(fexstate->args);
00103 else
00104 elog(ERROR, "could not identify CTID variable");
00105
00106 itemptr = (ItemPointer)
00107 DatumGetPointer(ExecEvalExprSwitchContext(exstate,
00108 econtext,
00109 &isNull,
00110 NULL));
00111 if (!isNull &&
00112 ItemPointerIsValid(itemptr) &&
00113 ItemPointerGetBlockNumber(itemptr) < nblocks)
00114 {
00115 if (numTids >= numAllocTids)
00116 {
00117 numAllocTids *= 2;
00118 tidList = (ItemPointerData *)
00119 repalloc(tidList,
00120 numAllocTids * sizeof(ItemPointerData));
00121 }
00122 tidList[numTids++] = *itemptr;
00123 }
00124 }
00125 else if (expr && IsA(expr, ScalarArrayOpExpr))
00126 {
00127 ScalarArrayOpExprState *saexstate = (ScalarArrayOpExprState *) exstate;
00128 Datum arraydatum;
00129 ArrayType *itemarray;
00130 Datum *ipdatums;
00131 bool *ipnulls;
00132 int ndatums;
00133 int i;
00134
00135 exstate = (ExprState *) lsecond(saexstate->fxprstate.args);
00136 arraydatum = ExecEvalExprSwitchContext(exstate,
00137 econtext,
00138 &isNull,
00139 NULL);
00140 if (isNull)
00141 continue;
00142 itemarray = DatumGetArrayTypeP(arraydatum);
00143 deconstruct_array(itemarray,
00144 TIDOID, SizeOfIptrData, false, 's',
00145 &ipdatums, &ipnulls, &ndatums);
00146 if (numTids + ndatums > numAllocTids)
00147 {
00148 numAllocTids = numTids + ndatums;
00149 tidList = (ItemPointerData *)
00150 repalloc(tidList,
00151 numAllocTids * sizeof(ItemPointerData));
00152 }
00153 for (i = 0; i < ndatums; i++)
00154 {
00155 if (!ipnulls[i])
00156 {
00157 itemptr = (ItemPointer) DatumGetPointer(ipdatums[i]);
00158 if (ItemPointerIsValid(itemptr) &&
00159 ItemPointerGetBlockNumber(itemptr) < nblocks)
00160 tidList[numTids++] = *itemptr;
00161 }
00162 }
00163 pfree(ipdatums);
00164 pfree(ipnulls);
00165 }
00166 else if (expr && IsA(expr, CurrentOfExpr))
00167 {
00168 CurrentOfExpr *cexpr = (CurrentOfExpr *) expr;
00169 ItemPointerData cursor_tid;
00170
00171 if (execCurrentOf(cexpr, econtext,
00172 RelationGetRelid(tidstate->ss.ss_currentRelation),
00173 &cursor_tid))
00174 {
00175 if (numTids >= numAllocTids)
00176 {
00177 numAllocTids *= 2;
00178 tidList = (ItemPointerData *)
00179 repalloc(tidList,
00180 numAllocTids * sizeof(ItemPointerData));
00181 }
00182 tidList[numTids++] = cursor_tid;
00183 tidstate->tss_isCurrentOf = true;
00184 }
00185 }
00186 else
00187 elog(ERROR, "could not identify CTID expression");
00188 }
00189
00190
00191
00192
00193
00194
00195
00196 if (numTids > 1)
00197 {
00198 int lastTid;
00199 int i;
00200
00201
00202 Assert(!tidstate->tss_isCurrentOf);
00203
00204 qsort((void *) tidList, numTids, sizeof(ItemPointerData),
00205 itemptr_comparator);
00206 lastTid = 0;
00207 for (i = 1; i < numTids; i++)
00208 {
00209 if (!ItemPointerEquals(&tidList[lastTid], &tidList[i]))
00210 tidList[++lastTid] = tidList[i];
00211 }
00212 numTids = lastTid + 1;
00213 }
00214
00215 tidstate->tss_TidList = tidList;
00216 tidstate->tss_NumTids = numTids;
00217 tidstate->tss_TidPtr = -1;
00218 }
00219
00220
00221
00222
00223 static int
00224 itemptr_comparator(const void *a, const void *b)
00225 {
00226 const ItemPointerData *ipa = (const ItemPointerData *) a;
00227 const ItemPointerData *ipb = (const ItemPointerData *) b;
00228 BlockNumber ba = ItemPointerGetBlockNumber(ipa);
00229 BlockNumber bb = ItemPointerGetBlockNumber(ipb);
00230 OffsetNumber oa = ItemPointerGetOffsetNumber(ipa);
00231 OffsetNumber ob = ItemPointerGetOffsetNumber(ipb);
00232
00233 if (ba < bb)
00234 return -1;
00235 if (ba > bb)
00236 return 1;
00237 if (oa < ob)
00238 return -1;
00239 if (oa > ob)
00240 return 1;
00241 return 0;
00242 }
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 static TupleTableSlot *
00253 TidNext(TidScanState *node)
00254 {
00255 EState *estate;
00256 ScanDirection direction;
00257 Snapshot snapshot;
00258 Relation heapRelation;
00259 HeapTuple tuple;
00260 TupleTableSlot *slot;
00261 Buffer buffer = InvalidBuffer;
00262 ItemPointerData *tidList;
00263 int numTids;
00264 bool bBackward;
00265
00266
00267
00268
00269 estate = node->ss.ps.state;
00270 direction = estate->es_direction;
00271 snapshot = estate->es_snapshot;
00272 heapRelation = node->ss.ss_currentRelation;
00273 slot = node->ss.ss_ScanTupleSlot;
00274
00275
00276
00277
00278 if (node->tss_TidList == NULL)
00279 TidListCreate(node);
00280
00281 tidList = node->tss_TidList;
00282 numTids = node->tss_NumTids;
00283
00284 tuple = &(node->tss_htup);
00285
00286
00287
00288
00289 bBackward = ScanDirectionIsBackward(direction);
00290 if (bBackward)
00291 {
00292 if (node->tss_TidPtr < 0)
00293 {
00294
00295 node->tss_TidPtr = numTids - 1;
00296 }
00297 else
00298 node->tss_TidPtr--;
00299 }
00300 else
00301 {
00302 if (node->tss_TidPtr < 0)
00303 {
00304
00305 node->tss_TidPtr = 0;
00306 }
00307 else
00308 node->tss_TidPtr++;
00309 }
00310
00311 while (node->tss_TidPtr >= 0 && node->tss_TidPtr < numTids)
00312 {
00313 tuple->t_self = tidList[node->tss_TidPtr];
00314
00315
00316
00317
00318
00319
00320 if (node->tss_isCurrentOf)
00321 heap_get_latest_tid(heapRelation, snapshot, &tuple->t_self);
00322
00323 if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
00324 {
00325
00326
00327
00328
00329
00330
00331
00332 ExecStoreTuple(tuple,
00333 slot,
00334 buffer,
00335 false);
00336
00337
00338
00339
00340
00341 ReleaseBuffer(buffer);
00342
00343 return slot;
00344 }
00345
00346 if (bBackward)
00347 node->tss_TidPtr--;
00348 else
00349 node->tss_TidPtr++;
00350 }
00351
00352
00353
00354
00355
00356 return ExecClearTuple(slot);
00357 }
00358
00359
00360
00361
00362 static bool
00363 TidRecheck(TidScanState *node, TupleTableSlot *slot)
00364 {
00365
00366
00367
00368
00369
00370 return true;
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 TupleTableSlot *
00393 ExecTidScan(TidScanState *node)
00394 {
00395 return ExecScan(&node->ss,
00396 (ExecScanAccessMtd) TidNext,
00397 (ExecScanRecheckMtd) TidRecheck);
00398 }
00399
00400
00401
00402
00403
00404 void
00405 ExecReScanTidScan(TidScanState *node)
00406 {
00407 if (node->tss_TidList)
00408 pfree(node->tss_TidList);
00409 node->tss_TidList = NULL;
00410 node->tss_NumTids = 0;
00411 node->tss_TidPtr = -1;
00412
00413 ExecScanReScan(&node->ss);
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423 void
00424 ExecEndTidScan(TidScanState *node)
00425 {
00426
00427
00428
00429 ExecFreeExprContext(&node->ss.ps);
00430
00431
00432
00433
00434 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
00435 ExecClearTuple(node->ss.ss_ScanTupleSlot);
00436
00437
00438
00439
00440 ExecCloseScanRelation(node->ss.ss_currentRelation);
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450 void
00451 ExecTidMarkPos(TidScanState *node)
00452 {
00453 node->tss_MarkTidPtr = node->tss_TidPtr;
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 void
00466 ExecTidRestrPos(TidScanState *node)
00467 {
00468 node->tss_TidPtr = node->tss_MarkTidPtr;
00469 }
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 TidScanState *
00483 ExecInitTidScan(TidScan *node, EState *estate, int eflags)
00484 {
00485 TidScanState *tidstate;
00486 Relation currentRelation;
00487
00488
00489
00490
00491 tidstate = makeNode(TidScanState);
00492 tidstate->ss.ps.plan = (Plan *) node;
00493 tidstate->ss.ps.state = estate;
00494
00495
00496
00497
00498
00499
00500 ExecAssignExprContext(estate, &tidstate->ss.ps);
00501
00502 tidstate->ss.ps.ps_TupFromTlist = false;
00503
00504
00505
00506
00507 tidstate->ss.ps.targetlist = (List *)
00508 ExecInitExpr((Expr *) node->scan.plan.targetlist,
00509 (PlanState *) tidstate);
00510 tidstate->ss.ps.qual = (List *)
00511 ExecInitExpr((Expr *) node->scan.plan.qual,
00512 (PlanState *) tidstate);
00513
00514 tidstate->tss_tidquals = (List *)
00515 ExecInitExpr((Expr *) node->tidquals,
00516 (PlanState *) tidstate);
00517
00518
00519
00520
00521 ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
00522 ExecInitScanTupleSlot(estate, &tidstate->ss);
00523
00524
00525
00526
00527 tidstate->tss_TidList = NULL;
00528 tidstate->tss_NumTids = 0;
00529 tidstate->tss_TidPtr = -1;
00530
00531
00532
00533
00534 currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
00535
00536 tidstate->ss.ss_currentRelation = currentRelation;
00537 tidstate->ss.ss_currentScanDesc = NULL;
00538
00539
00540
00541
00542 ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation));
00543
00544
00545
00546
00547 ExecAssignResultTypeFromTL(&tidstate->ss.ps);
00548 ExecAssignScanProjectionInfo(&tidstate->ss);
00549
00550
00551
00552
00553 return tidstate;
00554 }