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
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "postgres.h"
00039
00040 #include "access/htup_details.h"
00041 #include "access/sysattr.h"
00042 #include "access/transam.h"
00043 #include "access/xact.h"
00044 #include "catalog/namespace.h"
00045 #include "commands/trigger.h"
00046 #include "executor/execdebug.h"
00047 #include "foreign/fdwapi.h"
00048 #include "mb/pg_wchar.h"
00049 #include "miscadmin.h"
00050 #include "optimizer/clauses.h"
00051 #include "parser/parsetree.h"
00052 #include "storage/bufmgr.h"
00053 #include "storage/lmgr.h"
00054 #include "tcop/utility.h"
00055 #include "utils/acl.h"
00056 #include "utils/lsyscache.h"
00057 #include "utils/memutils.h"
00058 #include "utils/snapmgr.h"
00059 #include "utils/tqual.h"
00060
00061
00062
00063 ExecutorStart_hook_type ExecutorStart_hook = NULL;
00064 ExecutorRun_hook_type ExecutorRun_hook = NULL;
00065 ExecutorFinish_hook_type ExecutorFinish_hook = NULL;
00066 ExecutorEnd_hook_type ExecutorEnd_hook = NULL;
00067
00068
00069 ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook = NULL;
00070
00071
00072 static void InitPlan(QueryDesc *queryDesc, int eflags);
00073 static void CheckValidRowMarkRel(Relation rel, RowMarkType markType);
00074 static void ExecPostprocessPlan(EState *estate);
00075 static void ExecEndPlan(PlanState *planstate, EState *estate);
00076 static void ExecutePlan(EState *estate, PlanState *planstate,
00077 CmdType operation,
00078 bool sendTuples,
00079 long numberTuples,
00080 ScanDirection direction,
00081 DestReceiver *dest);
00082 static bool ExecCheckRTEPerms(RangeTblEntry *rte);
00083 static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
00084 static char *ExecBuildSlotValueDescription(TupleTableSlot *slot,
00085 int maxfieldlen);
00086 static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate,
00087 Plan *planTree);
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 void
00115 ExecutorStart(QueryDesc *queryDesc, int eflags)
00116 {
00117 if (ExecutorStart_hook)
00118 (*ExecutorStart_hook) (queryDesc, eflags);
00119 else
00120 standard_ExecutorStart(queryDesc, eflags);
00121 }
00122
00123 void
00124 standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
00125 {
00126 EState *estate;
00127 MemoryContext oldcontext;
00128
00129
00130 Assert(queryDesc != NULL);
00131 Assert(queryDesc->estate == NULL);
00132
00133
00134
00135
00136
00137 if (XactReadOnly && !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
00138 ExecCheckXactReadOnly(queryDesc->plannedstmt);
00139
00140
00141
00142
00143 estate = CreateExecutorState();
00144 queryDesc->estate = estate;
00145
00146 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
00147
00148
00149
00150
00151
00152 estate->es_param_list_info = queryDesc->params;
00153
00154 if (queryDesc->plannedstmt->nParamExec > 0)
00155 estate->es_param_exec_vals = (ParamExecData *)
00156 palloc0(queryDesc->plannedstmt->nParamExec * sizeof(ParamExecData));
00157
00158
00159
00160
00161 switch (queryDesc->operation)
00162 {
00163 case CMD_SELECT:
00164
00165
00166
00167
00168
00169 if (queryDesc->plannedstmt->rowMarks != NIL ||
00170 queryDesc->plannedstmt->hasModifyingCTE)
00171 estate->es_output_cid = GetCurrentCommandId(true);
00172
00173
00174
00175
00176
00177
00178
00179 if (!queryDesc->plannedstmt->hasModifyingCTE)
00180 eflags |= EXEC_FLAG_SKIP_TRIGGERS;
00181 break;
00182
00183 case CMD_INSERT:
00184 case CMD_DELETE:
00185 case CMD_UPDATE:
00186 estate->es_output_cid = GetCurrentCommandId(true);
00187 break;
00188
00189 default:
00190 elog(ERROR, "unrecognized operation code: %d",
00191 (int) queryDesc->operation);
00192 break;
00193 }
00194
00195
00196
00197
00198 estate->es_snapshot = RegisterSnapshot(queryDesc->snapshot);
00199 estate->es_crosscheck_snapshot = RegisterSnapshot(queryDesc->crosscheck_snapshot);
00200 estate->es_top_eflags = eflags;
00201 estate->es_instrument = queryDesc->instrument_options;
00202
00203
00204
00205
00206 InitPlan(queryDesc, eflags);
00207
00208
00209
00210
00211
00212 if (!(eflags & (EXEC_FLAG_SKIP_TRIGGERS | EXEC_FLAG_EXPLAIN_ONLY)))
00213 AfterTriggerBeginQuery();
00214
00215 MemoryContextSwitchTo(oldcontext);
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 void
00248 ExecutorRun(QueryDesc *queryDesc,
00249 ScanDirection direction, long count)
00250 {
00251 if (ExecutorRun_hook)
00252 (*ExecutorRun_hook) (queryDesc, direction, count);
00253 else
00254 standard_ExecutorRun(queryDesc, direction, count);
00255 }
00256
00257 void
00258 standard_ExecutorRun(QueryDesc *queryDesc,
00259 ScanDirection direction, long count)
00260 {
00261 EState *estate;
00262 CmdType operation;
00263 DestReceiver *dest;
00264 bool sendTuples;
00265 MemoryContext oldcontext;
00266
00267
00268 Assert(queryDesc != NULL);
00269
00270 estate = queryDesc->estate;
00271
00272 Assert(estate != NULL);
00273 Assert(!(estate->es_top_eflags & EXEC_FLAG_EXPLAIN_ONLY));
00274
00275
00276
00277
00278 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
00279
00280
00281 if (queryDesc->totaltime)
00282 InstrStartNode(queryDesc->totaltime);
00283
00284
00285
00286
00287 operation = queryDesc->operation;
00288 dest = queryDesc->dest;
00289
00290
00291
00292
00293 estate->es_processed = 0;
00294 estate->es_lastoid = InvalidOid;
00295
00296 sendTuples = (operation == CMD_SELECT ||
00297 queryDesc->plannedstmt->hasReturning);
00298
00299 if (sendTuples)
00300 (*dest->rStartup) (dest, operation, queryDesc->tupDesc);
00301
00302
00303
00304
00305 if (!ScanDirectionIsNoMovement(direction))
00306 ExecutePlan(estate,
00307 queryDesc->planstate,
00308 operation,
00309 sendTuples,
00310 count,
00311 direction,
00312 dest);
00313
00314
00315
00316
00317 if (sendTuples)
00318 (*dest->rShutdown) (dest);
00319
00320 if (queryDesc->totaltime)
00321 InstrStopNode(queryDesc->totaltime, estate->es_processed);
00322
00323 MemoryContextSwitchTo(oldcontext);
00324 }
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 void
00341 ExecutorFinish(QueryDesc *queryDesc)
00342 {
00343 if (ExecutorFinish_hook)
00344 (*ExecutorFinish_hook) (queryDesc);
00345 else
00346 standard_ExecutorFinish(queryDesc);
00347 }
00348
00349 void
00350 standard_ExecutorFinish(QueryDesc *queryDesc)
00351 {
00352 EState *estate;
00353 MemoryContext oldcontext;
00354
00355
00356 Assert(queryDesc != NULL);
00357
00358 estate = queryDesc->estate;
00359
00360 Assert(estate != NULL);
00361 Assert(!(estate->es_top_eflags & EXEC_FLAG_EXPLAIN_ONLY));
00362
00363
00364 Assert(!estate->es_finished);
00365
00366
00367 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
00368
00369
00370 if (queryDesc->totaltime)
00371 InstrStartNode(queryDesc->totaltime);
00372
00373
00374 ExecPostprocessPlan(estate);
00375
00376
00377 if (!(estate->es_top_eflags & EXEC_FLAG_SKIP_TRIGGERS))
00378 AfterTriggerEndQuery(estate);
00379
00380 if (queryDesc->totaltime)
00381 InstrStopNode(queryDesc->totaltime, 0);
00382
00383 MemoryContextSwitchTo(oldcontext);
00384
00385 estate->es_finished = true;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 void
00401 ExecutorEnd(QueryDesc *queryDesc)
00402 {
00403 if (ExecutorEnd_hook)
00404 (*ExecutorEnd_hook) (queryDesc);
00405 else
00406 standard_ExecutorEnd(queryDesc);
00407 }
00408
00409 void
00410 standard_ExecutorEnd(QueryDesc *queryDesc)
00411 {
00412 EState *estate;
00413 MemoryContext oldcontext;
00414
00415
00416 Assert(queryDesc != NULL);
00417
00418 estate = queryDesc->estate;
00419
00420 Assert(estate != NULL);
00421
00422
00423
00424
00425
00426
00427 Assert(estate->es_finished ||
00428 (estate->es_top_eflags & EXEC_FLAG_EXPLAIN_ONLY));
00429
00430
00431
00432
00433 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
00434
00435 ExecEndPlan(queryDesc->planstate, estate);
00436
00437
00438 UnregisterSnapshot(estate->es_snapshot);
00439 UnregisterSnapshot(estate->es_crosscheck_snapshot);
00440
00441
00442
00443
00444 MemoryContextSwitchTo(oldcontext);
00445
00446
00447
00448
00449
00450 FreeExecutorState(estate);
00451
00452
00453 queryDesc->tupDesc = NULL;
00454 queryDesc->estate = NULL;
00455 queryDesc->planstate = NULL;
00456 queryDesc->totaltime = NULL;
00457 }
00458
00459
00460
00461
00462
00463
00464
00465
00466 void
00467 ExecutorRewind(QueryDesc *queryDesc)
00468 {
00469 EState *estate;
00470 MemoryContext oldcontext;
00471
00472
00473 Assert(queryDesc != NULL);
00474
00475 estate = queryDesc->estate;
00476
00477 Assert(estate != NULL);
00478
00479
00480 Assert(queryDesc->operation == CMD_SELECT);
00481
00482
00483
00484
00485 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
00486
00487
00488
00489
00490 ExecReScan(queryDesc->planstate);
00491
00492 MemoryContextSwitchTo(oldcontext);
00493 }
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 bool
00504 ExecCheckRTPerms(List *rangeTable, bool ereport_on_violation)
00505 {
00506 ListCell *l;
00507 bool result = true;
00508
00509 foreach(l, rangeTable)
00510 {
00511 RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
00512
00513 result = ExecCheckRTEPerms(rte);
00514 if (!result)
00515 {
00516 Assert(rte->rtekind == RTE_RELATION);
00517 if (ereport_on_violation)
00518 aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
00519 get_rel_name(rte->relid));
00520 return false;
00521 }
00522 }
00523
00524 if (ExecutorCheckPerms_hook)
00525 result = (*ExecutorCheckPerms_hook) (rangeTable,
00526 ereport_on_violation);
00527 return result;
00528 }
00529
00530
00531
00532
00533
00534 static bool
00535 ExecCheckRTEPerms(RangeTblEntry *rte)
00536 {
00537 AclMode requiredPerms;
00538 AclMode relPerms;
00539 AclMode remainingPerms;
00540 Oid relOid;
00541 Oid userid;
00542 Bitmapset *tmpset;
00543 int col;
00544
00545
00546
00547
00548
00549
00550 if (rte->rtekind != RTE_RELATION)
00551 return true;
00552
00553
00554
00555
00556 requiredPerms = rte->requiredPerms;
00557 if (requiredPerms == 0)
00558 return true;
00559
00560 relOid = rte->relid;
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
00571
00572
00573
00574
00575
00576
00577 relPerms = pg_class_aclmask(relOid, userid, requiredPerms, ACLMASK_ALL);
00578 remainingPerms = requiredPerms & ~relPerms;
00579 if (remainingPerms != 0)
00580 {
00581
00582
00583
00584
00585 if (remainingPerms & ~(ACL_SELECT | ACL_INSERT | ACL_UPDATE))
00586 return false;
00587
00588
00589
00590
00591
00592
00593
00594
00595 if (remainingPerms & ACL_SELECT)
00596 {
00597
00598
00599
00600
00601
00602 if (bms_is_empty(rte->selectedCols))
00603 {
00604 if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
00605 ACLMASK_ANY) != ACLCHECK_OK)
00606 return false;
00607 }
00608
00609 tmpset = bms_copy(rte->selectedCols);
00610 while ((col = bms_first_member(tmpset)) >= 0)
00611 {
00612
00613 col += FirstLowInvalidHeapAttributeNumber;
00614 if (col == InvalidAttrNumber)
00615 {
00616
00617 if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
00618 ACLMASK_ALL) != ACLCHECK_OK)
00619 return false;
00620 }
00621 else
00622 {
00623 if (pg_attribute_aclcheck(relOid, col, userid,
00624 ACL_SELECT) != ACLCHECK_OK)
00625 return false;
00626 }
00627 }
00628 bms_free(tmpset);
00629 }
00630
00631
00632
00633
00634
00635 remainingPerms &= ~ACL_SELECT;
00636 if (remainingPerms != 0)
00637 {
00638
00639
00640
00641
00642
00643
00644 if (bms_is_empty(rte->modifiedCols))
00645 {
00646 if (pg_attribute_aclcheck_all(relOid, userid, remainingPerms,
00647 ACLMASK_ANY) != ACLCHECK_OK)
00648 return false;
00649 }
00650
00651 tmpset = bms_copy(rte->modifiedCols);
00652 while ((col = bms_first_member(tmpset)) >= 0)
00653 {
00654
00655 col += FirstLowInvalidHeapAttributeNumber;
00656 if (col == InvalidAttrNumber)
00657 {
00658
00659 elog(ERROR, "whole-row update is not implemented");
00660 }
00661 else
00662 {
00663 if (pg_attribute_aclcheck(relOid, col, userid,
00664 remainingPerms) != ACLCHECK_OK)
00665 return false;
00666 }
00667 }
00668 bms_free(tmpset);
00669 }
00670 }
00671 return true;
00672 }
00673
00674
00675
00676
00677
00678
00679
00680
00681 static void
00682 ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
00683 {
00684 ListCell *l;
00685
00686
00687 foreach(l, plannedstmt->rtable)
00688 {
00689 RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
00690
00691 if (rte->rtekind != RTE_RELATION)
00692 continue;
00693
00694 if ((rte->requiredPerms & (~ACL_SELECT)) == 0)
00695 continue;
00696
00697 if (isTempNamespace(get_rel_namespace(rte->relid)))
00698 continue;
00699
00700 PreventCommandIfReadOnly(CreateCommandTag((Node *) plannedstmt));
00701 }
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712 static void
00713 InitPlan(QueryDesc *queryDesc, int eflags)
00714 {
00715 CmdType operation = queryDesc->operation;
00716 PlannedStmt *plannedstmt = queryDesc->plannedstmt;
00717 Plan *plan = plannedstmt->planTree;
00718 List *rangeTable = plannedstmt->rtable;
00719 EState *estate = queryDesc->estate;
00720 PlanState *planstate;
00721 TupleDesc tupType;
00722 ListCell *l;
00723 int i;
00724
00725
00726
00727
00728 ExecCheckRTPerms(rangeTable, true);
00729
00730
00731
00732
00733 estate->es_range_table = rangeTable;
00734 estate->es_plannedstmt = plannedstmt;
00735
00736
00737
00738
00739
00740
00741
00742 if (plannedstmt->resultRelations)
00743 {
00744 List *resultRelations = plannedstmt->resultRelations;
00745 int numResultRelations = list_length(resultRelations);
00746 ResultRelInfo *resultRelInfos;
00747 ResultRelInfo *resultRelInfo;
00748
00749 resultRelInfos = (ResultRelInfo *)
00750 palloc(numResultRelations * sizeof(ResultRelInfo));
00751 resultRelInfo = resultRelInfos;
00752 foreach(l, resultRelations)
00753 {
00754 Index resultRelationIndex = lfirst_int(l);
00755 Oid resultRelationOid;
00756 Relation resultRelation;
00757
00758 resultRelationOid = getrelid(resultRelationIndex, rangeTable);
00759 resultRelation = heap_open(resultRelationOid, RowExclusiveLock);
00760 InitResultRelInfo(resultRelInfo,
00761 resultRelation,
00762 resultRelationIndex,
00763 estate->es_instrument);
00764 resultRelInfo++;
00765 }
00766 estate->es_result_relations = resultRelInfos;
00767 estate->es_num_result_relations = numResultRelations;
00768
00769 estate->es_result_relation_info = NULL;
00770 }
00771 else
00772 {
00773
00774
00775
00776 estate->es_result_relations = NULL;
00777 estate->es_num_result_relations = 0;
00778 estate->es_result_relation_info = NULL;
00779 }
00780
00781
00782
00783
00784
00785
00786 estate->es_rowMarks = NIL;
00787 foreach(l, plannedstmt->rowMarks)
00788 {
00789 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
00790 Oid relid;
00791 Relation relation;
00792 ExecRowMark *erm;
00793
00794
00795 if (rc->isParent)
00796 continue;
00797
00798 switch (rc->markType)
00799 {
00800 case ROW_MARK_EXCLUSIVE:
00801 case ROW_MARK_NOKEYEXCLUSIVE:
00802 case ROW_MARK_SHARE:
00803 case ROW_MARK_KEYSHARE:
00804 relid = getrelid(rc->rti, rangeTable);
00805 relation = heap_open(relid, RowShareLock);
00806 break;
00807 case ROW_MARK_REFERENCE:
00808 relid = getrelid(rc->rti, rangeTable);
00809 relation = heap_open(relid, AccessShareLock);
00810 break;
00811 case ROW_MARK_COPY:
00812
00813 relation = NULL;
00814 break;
00815 default:
00816 elog(ERROR, "unrecognized markType: %d", rc->markType);
00817 relation = NULL;
00818 break;
00819 }
00820
00821
00822 if (relation)
00823 CheckValidRowMarkRel(relation, rc->markType);
00824
00825 erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
00826 erm->relation = relation;
00827 erm->rti = rc->rti;
00828 erm->prti = rc->prti;
00829 erm->rowmarkId = rc->rowmarkId;
00830 erm->markType = rc->markType;
00831 erm->noWait = rc->noWait;
00832 ItemPointerSetInvalid(&(erm->curCtid));
00833 estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
00834 }
00835
00836
00837
00838
00839 estate->es_tupleTable = NIL;
00840 estate->es_trig_tuple_slot = NULL;
00841 estate->es_trig_oldtup_slot = NULL;
00842 estate->es_trig_newtup_slot = NULL;
00843
00844
00845 estate->es_epqTuple = NULL;
00846 estate->es_epqTupleSet = NULL;
00847 estate->es_epqScanDone = NULL;
00848
00849
00850
00851
00852
00853
00854 Assert(estate->es_subplanstates == NIL);
00855 i = 1;
00856 foreach(l, plannedstmt->subplans)
00857 {
00858 Plan *subplan = (Plan *) lfirst(l);
00859 PlanState *subplanstate;
00860 int sp_eflags;
00861
00862
00863
00864
00865
00866
00867 sp_eflags = eflags & EXEC_FLAG_EXPLAIN_ONLY;
00868 if (bms_is_member(i, plannedstmt->rewindPlanIDs))
00869 sp_eflags |= EXEC_FLAG_REWIND;
00870
00871 subplanstate = ExecInitNode(subplan, estate, sp_eflags);
00872
00873 estate->es_subplanstates = lappend(estate->es_subplanstates,
00874 subplanstate);
00875
00876 i++;
00877 }
00878
00879
00880
00881
00882
00883
00884 planstate = ExecInitNode(plan, estate, eflags);
00885
00886
00887
00888
00889 tupType = ExecGetResultType(planstate);
00890
00891
00892
00893
00894
00895 if (operation == CMD_SELECT)
00896 {
00897 bool junk_filter_needed = false;
00898 ListCell *tlist;
00899
00900 foreach(tlist, plan->targetlist)
00901 {
00902 TargetEntry *tle = (TargetEntry *) lfirst(tlist);
00903
00904 if (tle->resjunk)
00905 {
00906 junk_filter_needed = true;
00907 break;
00908 }
00909 }
00910
00911 if (junk_filter_needed)
00912 {
00913 JunkFilter *j;
00914
00915 j = ExecInitJunkFilter(planstate->plan->targetlist,
00916 tupType->tdhasoid,
00917 ExecInitExtraTupleSlot(estate));
00918 estate->es_junkFilter = j;
00919
00920
00921 tupType = j->jf_cleanTupType;
00922 }
00923 }
00924
00925 queryDesc->tupDesc = tupType;
00926 queryDesc->planstate = planstate;
00927 }
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938 void
00939 CheckValidResultRel(Relation resultRel, CmdType operation)
00940 {
00941 TriggerDesc *trigDesc = resultRel->trigdesc;
00942 FdwRoutine *fdwroutine;
00943
00944 switch (resultRel->rd_rel->relkind)
00945 {
00946 case RELKIND_RELATION:
00947
00948 break;
00949 case RELKIND_SEQUENCE:
00950 ereport(ERROR,
00951 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00952 errmsg("cannot change sequence \"%s\"",
00953 RelationGetRelationName(resultRel))));
00954 break;
00955 case RELKIND_TOASTVALUE:
00956 ereport(ERROR,
00957 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00958 errmsg("cannot change TOAST relation \"%s\"",
00959 RelationGetRelationName(resultRel))));
00960 break;
00961 case RELKIND_VIEW:
00962
00963
00964
00965
00966
00967
00968
00969 switch (operation)
00970 {
00971 case CMD_INSERT:
00972 if (!trigDesc || !trigDesc->trig_insert_instead_row)
00973 ereport(ERROR,
00974 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00975 errmsg("cannot insert into view \"%s\"",
00976 RelationGetRelationName(resultRel)),
00977 errhint("To make the view insertable, provide an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger.")));
00978 break;
00979 case CMD_UPDATE:
00980 if (!trigDesc || !trigDesc->trig_update_instead_row)
00981 ereport(ERROR,
00982 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00983 errmsg("cannot update view \"%s\"",
00984 RelationGetRelationName(resultRel)),
00985 errhint("To make the view updatable, provide an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger.")));
00986 break;
00987 case CMD_DELETE:
00988 if (!trigDesc || !trigDesc->trig_delete_instead_row)
00989 ereport(ERROR,
00990 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00991 errmsg("cannot delete from view \"%s\"",
00992 RelationGetRelationName(resultRel)),
00993 errhint("To make the view updatable, provide an unconditional ON DELETE DO INSTEAD rule or an INSTEAD OF DELETE trigger.")));
00994 break;
00995 default:
00996 elog(ERROR, "unrecognized CmdType: %d", (int) operation);
00997 break;
00998 }
00999 break;
01000 case RELKIND_MATVIEW:
01001 ereport(ERROR,
01002 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01003 errmsg("cannot change materialized view \"%s\"",
01004 RelationGetRelationName(resultRel))));
01005 break;
01006 case RELKIND_FOREIGN_TABLE:
01007
01008 fdwroutine = GetFdwRoutineForRelation(resultRel, false);
01009 switch (operation)
01010 {
01011 case CMD_INSERT:
01012 if (fdwroutine->ExecForeignInsert == NULL)
01013 ereport(ERROR,
01014 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01015 errmsg("cannot insert into foreign table \"%s\"",
01016 RelationGetRelationName(resultRel))));
01017 break;
01018 case CMD_UPDATE:
01019 if (fdwroutine->ExecForeignUpdate == NULL)
01020 ereport(ERROR,
01021 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01022 errmsg("cannot update foreign table \"%s\"",
01023 RelationGetRelationName(resultRel))));
01024 break;
01025 case CMD_DELETE:
01026 if (fdwroutine->ExecForeignDelete == NULL)
01027 ereport(ERROR,
01028 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01029 errmsg("cannot delete from foreign table \"%s\"",
01030 RelationGetRelationName(resultRel))));
01031 break;
01032 default:
01033 elog(ERROR, "unrecognized CmdType: %d", (int) operation);
01034 break;
01035 }
01036 break;
01037 default:
01038 ereport(ERROR,
01039 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01040 errmsg("cannot change relation \"%s\"",
01041 RelationGetRelationName(resultRel))));
01042 break;
01043 }
01044 }
01045
01046
01047
01048
01049
01050
01051
01052 static void
01053 CheckValidRowMarkRel(Relation rel, RowMarkType markType)
01054 {
01055 switch (rel->rd_rel->relkind)
01056 {
01057 case RELKIND_RELATION:
01058
01059 break;
01060 case RELKIND_SEQUENCE:
01061
01062 ereport(ERROR,
01063 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01064 errmsg("cannot lock rows in sequence \"%s\"",
01065 RelationGetRelationName(rel))));
01066 break;
01067 case RELKIND_TOASTVALUE:
01068
01069 ereport(ERROR,
01070 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01071 errmsg("cannot lock rows in TOAST relation \"%s\"",
01072 RelationGetRelationName(rel))));
01073 break;
01074 case RELKIND_VIEW:
01075
01076 ereport(ERROR,
01077 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01078 errmsg("cannot lock rows in view \"%s\"",
01079 RelationGetRelationName(rel))));
01080 break;
01081 case RELKIND_MATVIEW:
01082
01083 ereport(ERROR,
01084 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01085 errmsg("cannot lock rows in materialized view \"%s\"",
01086 RelationGetRelationName(rel))));
01087 break;
01088 case RELKIND_FOREIGN_TABLE:
01089
01090 ereport(ERROR,
01091 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01092 errmsg("cannot lock rows in foreign table \"%s\"",
01093 RelationGetRelationName(rel))));
01094 break;
01095 default:
01096 ereport(ERROR,
01097 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01098 errmsg("cannot lock rows in relation \"%s\"",
01099 RelationGetRelationName(rel))));
01100 break;
01101 }
01102 }
01103
01104
01105
01106
01107
01108
01109
01110
01111 void
01112 InitResultRelInfo(ResultRelInfo *resultRelInfo,
01113 Relation resultRelationDesc,
01114 Index resultRelationIndex,
01115 int instrument_options)
01116 {
01117 MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
01118 resultRelInfo->type = T_ResultRelInfo;
01119 resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
01120 resultRelInfo->ri_RelationDesc = resultRelationDesc;
01121 resultRelInfo->ri_NumIndices = 0;
01122 resultRelInfo->ri_IndexRelationDescs = NULL;
01123 resultRelInfo->ri_IndexRelationInfo = NULL;
01124
01125 resultRelInfo->ri_TrigDesc = CopyTriggerDesc(resultRelationDesc->trigdesc);
01126 if (resultRelInfo->ri_TrigDesc)
01127 {
01128 int n = resultRelInfo->ri_TrigDesc->numtriggers;
01129
01130 resultRelInfo->ri_TrigFunctions = (FmgrInfo *)
01131 palloc0(n * sizeof(FmgrInfo));
01132 resultRelInfo->ri_TrigWhenExprs = (List **)
01133 palloc0(n * sizeof(List *));
01134 if (instrument_options)
01135 resultRelInfo->ri_TrigInstrument = InstrAlloc(n, instrument_options);
01136 }
01137 else
01138 {
01139 resultRelInfo->ri_TrigFunctions = NULL;
01140 resultRelInfo->ri_TrigWhenExprs = NULL;
01141 resultRelInfo->ri_TrigInstrument = NULL;
01142 }
01143 if (resultRelationDesc->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
01144 resultRelInfo->ri_FdwRoutine = GetFdwRoutineForRelation(resultRelationDesc, true);
01145 else
01146 resultRelInfo->ri_FdwRoutine = NULL;
01147 resultRelInfo->ri_FdwState = NULL;
01148 resultRelInfo->ri_ConstraintExprs = NULL;
01149 resultRelInfo->ri_junkFilter = NULL;
01150 resultRelInfo->ri_projectReturning = NULL;
01151 }
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169 ResultRelInfo *
01170 ExecGetTriggerResultRel(EState *estate, Oid relid)
01171 {
01172 ResultRelInfo *rInfo;
01173 int nr;
01174 ListCell *l;
01175 Relation rel;
01176 MemoryContext oldcontext;
01177
01178
01179 rInfo = estate->es_result_relations;
01180 nr = estate->es_num_result_relations;
01181 while (nr > 0)
01182 {
01183 if (RelationGetRelid(rInfo->ri_RelationDesc) == relid)
01184 return rInfo;
01185 rInfo++;
01186 nr--;
01187 }
01188
01189 foreach(l, estate->es_trig_target_relations)
01190 {
01191 rInfo = (ResultRelInfo *) lfirst(l);
01192 if (RelationGetRelid(rInfo->ri_RelationDesc) == relid)
01193 return rInfo;
01194 }
01195
01196
01197
01198
01199
01200
01201
01202
01203 rel = heap_open(relid, NoLock);
01204
01205
01206
01207
01208 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
01209 rInfo = makeNode(ResultRelInfo);
01210 InitResultRelInfo(rInfo,
01211 rel,
01212 0,
01213 estate->es_instrument);
01214 estate->es_trig_target_relations =
01215 lappend(estate->es_trig_target_relations, rInfo);
01216 MemoryContextSwitchTo(oldcontext);
01217
01218
01219
01220
01221
01222
01223 return rInfo;
01224 }
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258 bool
01259 ExecContextForcesOids(PlanState *planstate, bool *hasoids)
01260 {
01261 ResultRelInfo *ri = planstate->state->es_result_relation_info;
01262
01263 if (ri != NULL)
01264 {
01265 Relation rel = ri->ri_RelationDesc;
01266
01267 if (rel != NULL)
01268 {
01269 *hasoids = rel->rd_rel->relhasoids;
01270 return true;
01271 }
01272 }
01273
01274 if (planstate->state->es_top_eflags & EXEC_FLAG_WITH_OIDS)
01275 {
01276 *hasoids = true;
01277 return true;
01278 }
01279 if (planstate->state->es_top_eflags & EXEC_FLAG_WITHOUT_OIDS)
01280 {
01281 *hasoids = false;
01282 return true;
01283 }
01284
01285 return false;
01286 }
01287
01288
01289
01290
01291
01292
01293
01294 static void
01295 ExecPostprocessPlan(EState *estate)
01296 {
01297 ListCell *lc;
01298
01299
01300
01301
01302 estate->es_direction = ForwardScanDirection;
01303
01304
01305
01306
01307
01308
01309 foreach(lc, estate->es_auxmodifytables)
01310 {
01311 PlanState *ps = (PlanState *) lfirst(lc);
01312
01313 for (;;)
01314 {
01315 TupleTableSlot *slot;
01316
01317
01318 ResetPerTupleExprContext(estate);
01319
01320 slot = ExecProcNode(ps);
01321
01322 if (TupIsNull(slot))
01323 break;
01324 }
01325 }
01326 }
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340 static void
01341 ExecEndPlan(PlanState *planstate, EState *estate)
01342 {
01343 ResultRelInfo *resultRelInfo;
01344 int i;
01345 ListCell *l;
01346
01347
01348
01349
01350 ExecEndNode(planstate);
01351
01352
01353
01354
01355 foreach(l, estate->es_subplanstates)
01356 {
01357 PlanState *subplanstate = (PlanState *) lfirst(l);
01358
01359 ExecEndNode(subplanstate);
01360 }
01361
01362
01363
01364
01365
01366
01367
01368 ExecResetTupleTable(estate->es_tupleTable, false);
01369
01370
01371
01372
01373 resultRelInfo = estate->es_result_relations;
01374 for (i = estate->es_num_result_relations; i > 0; i--)
01375 {
01376
01377 ExecCloseIndices(resultRelInfo);
01378 heap_close(resultRelInfo->ri_RelationDesc, NoLock);
01379 resultRelInfo++;
01380 }
01381
01382
01383
01384
01385 foreach(l, estate->es_trig_target_relations)
01386 {
01387 resultRelInfo = (ResultRelInfo *) lfirst(l);
01388
01389 ExecCloseIndices(resultRelInfo);
01390 heap_close(resultRelInfo->ri_RelationDesc, NoLock);
01391 }
01392
01393
01394
01395
01396 foreach(l, estate->es_rowMarks)
01397 {
01398 ExecRowMark *erm = (ExecRowMark *) lfirst(l);
01399
01400 if (erm->relation)
01401 heap_close(erm->relation, NoLock);
01402 }
01403 }
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417 static void
01418 ExecutePlan(EState *estate,
01419 PlanState *planstate,
01420 CmdType operation,
01421 bool sendTuples,
01422 long numberTuples,
01423 ScanDirection direction,
01424 DestReceiver *dest)
01425 {
01426 TupleTableSlot *slot;
01427 long current_tuple_count;
01428
01429
01430
01431
01432 current_tuple_count = 0;
01433
01434
01435
01436
01437 estate->es_direction = direction;
01438
01439
01440
01441
01442 for (;;)
01443 {
01444
01445 ResetPerTupleExprContext(estate);
01446
01447
01448
01449
01450 slot = ExecProcNode(planstate);
01451
01452
01453
01454
01455
01456 if (TupIsNull(slot))
01457 break;
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467 if (estate->es_junkFilter != NULL)
01468 slot = ExecFilterJunk(estate->es_junkFilter, slot);
01469
01470
01471
01472
01473
01474 if (sendTuples)
01475 (*dest->receiveSlot) (slot, dest);
01476
01477
01478
01479
01480
01481
01482 if (operation == CMD_SELECT)
01483 (estate->es_processed)++;
01484
01485
01486
01487
01488
01489
01490 current_tuple_count++;
01491 if (numberTuples && numberTuples == current_tuple_count)
01492 break;
01493 }
01494 }
01495
01496
01497
01498
01499
01500
01501
01502 static const char *
01503 ExecRelCheck(ResultRelInfo *resultRelInfo,
01504 TupleTableSlot *slot, EState *estate)
01505 {
01506 Relation rel = resultRelInfo->ri_RelationDesc;
01507 int ncheck = rel->rd_att->constr->num_check;
01508 ConstrCheck *check = rel->rd_att->constr->check;
01509 ExprContext *econtext;
01510 MemoryContext oldContext;
01511 List *qual;
01512 int i;
01513
01514
01515
01516
01517
01518
01519 if (resultRelInfo->ri_ConstraintExprs == NULL)
01520 {
01521 oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
01522 resultRelInfo->ri_ConstraintExprs =
01523 (List **) palloc(ncheck * sizeof(List *));
01524 for (i = 0; i < ncheck; i++)
01525 {
01526
01527 qual = make_ands_implicit(stringToNode(check[i].ccbin));
01528 resultRelInfo->ri_ConstraintExprs[i] = (List *)
01529 ExecPrepareExpr((Expr *) qual, estate);
01530 }
01531 MemoryContextSwitchTo(oldContext);
01532 }
01533
01534
01535
01536
01537
01538 econtext = GetPerTupleExprContext(estate);
01539
01540
01541 econtext->ecxt_scantuple = slot;
01542
01543
01544 for (i = 0; i < ncheck; i++)
01545 {
01546 qual = resultRelInfo->ri_ConstraintExprs[i];
01547
01548
01549
01550
01551
01552
01553 if (!ExecQual(qual, econtext, true))
01554 return check[i].ccname;
01555 }
01556
01557
01558 return NULL;
01559 }
01560
01561 void
01562 ExecConstraints(ResultRelInfo *resultRelInfo,
01563 TupleTableSlot *slot, EState *estate)
01564 {
01565 Relation rel = resultRelInfo->ri_RelationDesc;
01566 TupleConstr *constr = rel->rd_att->constr;
01567
01568 Assert(constr);
01569
01570 if (constr->has_not_null)
01571 {
01572 int natts = rel->rd_att->natts;
01573 int attrChk;
01574
01575 for (attrChk = 1; attrChk <= natts; attrChk++)
01576 {
01577 if (rel->rd_att->attrs[attrChk - 1]->attnotnull &&
01578 slot_attisnull(slot, attrChk))
01579 ereport(ERROR,
01580 (errcode(ERRCODE_NOT_NULL_VIOLATION),
01581 errmsg("null value in column \"%s\" violates not-null constraint",
01582 NameStr(rel->rd_att->attrs[attrChk - 1]->attname)),
01583 errdetail("Failing row contains %s.",
01584 ExecBuildSlotValueDescription(slot, 64)),
01585 errtablecol(rel, attrChk)));
01586 }
01587 }
01588
01589 if (constr->num_check > 0)
01590 {
01591 const char *failed;
01592
01593 if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
01594 ereport(ERROR,
01595 (errcode(ERRCODE_CHECK_VIOLATION),
01596 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
01597 RelationGetRelationName(rel), failed),
01598 errdetail("Failing row contains %s.",
01599 ExecBuildSlotValueDescription(slot, 64)),
01600 errtableconstraint(rel, failed)));
01601 }
01602 }
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612 static char *
01613 ExecBuildSlotValueDescription(TupleTableSlot *slot, int maxfieldlen)
01614 {
01615 StringInfoData buf;
01616 TupleDesc tupdesc = slot->tts_tupleDescriptor;
01617 int i;
01618
01619
01620 slot_getallattrs(slot);
01621
01622 initStringInfo(&buf);
01623
01624 appendStringInfoChar(&buf, '(');
01625
01626 for (i = 0; i < tupdesc->natts; i++)
01627 {
01628 char *val;
01629 int vallen;
01630
01631 if (slot->tts_isnull[i])
01632 val = "null";
01633 else
01634 {
01635 Oid foutoid;
01636 bool typisvarlena;
01637
01638 getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
01639 &foutoid, &typisvarlena);
01640 val = OidOutputFunctionCall(foutoid, slot->tts_values[i]);
01641 }
01642
01643 if (i > 0)
01644 appendStringInfoString(&buf, ", ");
01645
01646
01647 vallen = strlen(val);
01648 if (vallen <= maxfieldlen)
01649 appendStringInfoString(&buf, val);
01650 else
01651 {
01652 vallen = pg_mbcliplen(val, vallen, maxfieldlen);
01653 appendBinaryStringInfo(&buf, val, vallen);
01654 appendStringInfoString(&buf, "...");
01655 }
01656 }
01657
01658 appendStringInfoChar(&buf, ')');
01659
01660 return buf.data;
01661 }
01662
01663
01664
01665
01666
01667 ExecRowMark *
01668 ExecFindRowMark(EState *estate, Index rti)
01669 {
01670 ListCell *lc;
01671
01672 foreach(lc, estate->es_rowMarks)
01673 {
01674 ExecRowMark *erm = (ExecRowMark *) lfirst(lc);
01675
01676 if (erm->rti == rti)
01677 return erm;
01678 }
01679 elog(ERROR, "failed to find ExecRowMark for rangetable index %u", rti);
01680 return NULL;
01681 }
01682
01683
01684
01685
01686
01687
01688
01689
01690 ExecAuxRowMark *
01691 ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
01692 {
01693 ExecAuxRowMark *aerm = (ExecAuxRowMark *) palloc0(sizeof(ExecAuxRowMark));
01694 char resname[32];
01695
01696 aerm->rowmark = erm;
01697
01698
01699 if (erm->relation)
01700 {
01701 Assert(erm->markType != ROW_MARK_COPY);
01702
01703
01704 if (erm->rti != erm->prti)
01705 {
01706 snprintf(resname, sizeof(resname), "tableoid%u", erm->rowmarkId);
01707 aerm->toidAttNo = ExecFindJunkAttributeInTlist(targetlist,
01708 resname);
01709 if (!AttributeNumberIsValid(aerm->toidAttNo))
01710 elog(ERROR, "could not find junk %s column", resname);
01711 }
01712
01713
01714 snprintf(resname, sizeof(resname), "ctid%u", erm->rowmarkId);
01715 aerm->ctidAttNo = ExecFindJunkAttributeInTlist(targetlist,
01716 resname);
01717 if (!AttributeNumberIsValid(aerm->ctidAttNo))
01718 elog(ERROR, "could not find junk %s column", resname);
01719 }
01720 else
01721 {
01722 Assert(erm->markType == ROW_MARK_COPY);
01723
01724 snprintf(resname, sizeof(resname), "wholerow%u", erm->rowmarkId);
01725 aerm->wholeAttNo = ExecFindJunkAttributeInTlist(targetlist,
01726 resname);
01727 if (!AttributeNumberIsValid(aerm->wholeAttNo))
01728 elog(ERROR, "could not find junk %s column", resname);
01729 }
01730
01731 return aerm;
01732 }
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764 TupleTableSlot *
01765 EvalPlanQual(EState *estate, EPQState *epqstate,
01766 Relation relation, Index rti, int lockmode,
01767 ItemPointer tid, TransactionId priorXmax)
01768 {
01769 TupleTableSlot *slot;
01770 HeapTuple copyTuple;
01771
01772 Assert(rti > 0);
01773
01774
01775
01776
01777 copyTuple = EvalPlanQualFetch(estate, relation, lockmode,
01778 tid, priorXmax);
01779
01780 if (copyTuple == NULL)
01781 return NULL;
01782
01783
01784
01785
01786
01787 *tid = copyTuple->t_self;
01788
01789
01790
01791
01792 EvalPlanQualBegin(epqstate, estate);
01793
01794
01795
01796
01797
01798 EvalPlanQualSetTuple(epqstate, rti, copyTuple);
01799
01800
01801
01802
01803 EvalPlanQualFetchRowMarks(epqstate);
01804
01805
01806
01807
01808 slot = EvalPlanQualNext(epqstate);
01809
01810
01811
01812
01813
01814
01815
01816
01817 if (!TupIsNull(slot))
01818 (void) ExecMaterializeSlot(slot);
01819
01820
01821
01822
01823
01824
01825 EvalPlanQualSetTuple(epqstate, rti, NULL);
01826
01827 return slot;
01828 }
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847 HeapTuple
01848 EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
01849 ItemPointer tid, TransactionId priorXmax)
01850 {
01851 HeapTuple copyTuple = NULL;
01852 HeapTupleData tuple;
01853 SnapshotData SnapshotDirty;
01854
01855
01856
01857
01858
01859
01860 InitDirtySnapshot(SnapshotDirty);
01861 tuple.t_self = *tid;
01862 for (;;)
01863 {
01864 Buffer buffer;
01865
01866 if (heap_fetch(relation, &SnapshotDirty, &tuple, &buffer, true, NULL))
01867 {
01868 HTSU_Result test;
01869 HeapUpdateFailureData hufd;
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879 if (!TransactionIdEquals(HeapTupleHeaderGetXmin(tuple.t_data),
01880 priorXmax))
01881 {
01882 ReleaseBuffer(buffer);
01883 return NULL;
01884 }
01885
01886
01887 if (TransactionIdIsValid(SnapshotDirty.xmin))
01888 elog(ERROR, "t_xmin is uncommitted in tuple to be updated");
01889
01890
01891
01892
01893
01894 if (TransactionIdIsValid(SnapshotDirty.xmax))
01895 {
01896 ReleaseBuffer(buffer);
01897 XactLockTableWait(SnapshotDirty.xmax);
01898 continue;
01899 }
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912 if (TransactionIdIsCurrentTransactionId(priorXmax) &&
01913 HeapTupleHeaderGetCmin(tuple.t_data) >= estate->es_output_cid)
01914 {
01915 ReleaseBuffer(buffer);
01916 return NULL;
01917 }
01918
01919
01920
01921
01922 test = heap_lock_tuple(relation, &tuple,
01923 estate->es_output_cid,
01924 lockmode, false ,
01925 false, &buffer, &hufd);
01926
01927 ReleaseBuffer(buffer);
01928
01929 switch (test)
01930 {
01931 case HeapTupleSelfUpdated:
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945 ReleaseBuffer(buffer);
01946 return NULL;
01947
01948 case HeapTupleMayBeUpdated:
01949
01950 break;
01951
01952 case HeapTupleUpdated:
01953 ReleaseBuffer(buffer);
01954 if (IsolationUsesXactSnapshot())
01955 ereport(ERROR,
01956 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
01957 errmsg("could not serialize access due to concurrent update")));
01958 if (!ItemPointerEquals(&hufd.ctid, &tuple.t_self))
01959 {
01960
01961 tuple.t_self = hufd.ctid;
01962
01963 priorXmax = hufd.xmax;
01964 continue;
01965 }
01966
01967 return NULL;
01968
01969 default:
01970 ReleaseBuffer(buffer);
01971 elog(ERROR, "unrecognized heap_lock_tuple status: %u",
01972 test);
01973 return NULL;
01974 }
01975
01976
01977
01978
01979 copyTuple = heap_copytuple(&tuple);
01980 ReleaseBuffer(buffer);
01981 break;
01982 }
01983
01984
01985
01986
01987
01988 if (tuple.t_data == NULL)
01989 {
01990 ReleaseBuffer(buffer);
01991 return NULL;
01992 }
01993
01994
01995
01996
01997 if (!TransactionIdEquals(HeapTupleHeaderGetXmin(tuple.t_data),
01998 priorXmax))
01999 {
02000 ReleaseBuffer(buffer);
02001 return NULL;
02002 }
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016 if (ItemPointerEquals(&tuple.t_self, &tuple.t_data->t_ctid))
02017 {
02018
02019 ReleaseBuffer(buffer);
02020 return NULL;
02021 }
02022
02023
02024 tuple.t_self = tuple.t_data->t_ctid;
02025
02026 priorXmax = HeapTupleHeaderGetUpdateXid(tuple.t_data);
02027 ReleaseBuffer(buffer);
02028
02029 }
02030
02031
02032
02033
02034 return copyTuple;
02035 }
02036
02037
02038
02039
02040
02041
02042
02043
02044 void
02045 EvalPlanQualInit(EPQState *epqstate, EState *estate,
02046 Plan *subplan, List *auxrowmarks, int epqParam)
02047 {
02048
02049 epqstate->estate = NULL;
02050 epqstate->planstate = NULL;
02051 epqstate->origslot = NULL;
02052
02053 epqstate->plan = subplan;
02054 epqstate->arowMarks = auxrowmarks;
02055 epqstate->epqParam = epqParam;
02056 }
02057
02058
02059
02060
02061
02062
02063 void
02064 EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
02065 {
02066
02067 EvalPlanQualEnd(epqstate);
02068
02069 epqstate->plan = subplan;
02070
02071 epqstate->arowMarks = auxrowmarks;
02072 }
02073
02074
02075
02076
02077
02078
02079 void
02080 EvalPlanQualSetTuple(EPQState *epqstate, Index rti, HeapTuple tuple)
02081 {
02082 EState *estate = epqstate->estate;
02083
02084 Assert(rti > 0);
02085
02086
02087
02088
02089
02090 if (estate->es_epqTuple[rti - 1] != NULL)
02091 heap_freetuple(estate->es_epqTuple[rti - 1]);
02092 estate->es_epqTuple[rti - 1] = tuple;
02093 estate->es_epqTupleSet[rti - 1] = true;
02094 }
02095
02096
02097
02098
02099 HeapTuple
02100 EvalPlanQualGetTuple(EPQState *epqstate, Index rti)
02101 {
02102 EState *estate = epqstate->estate;
02103
02104 Assert(rti > 0);
02105
02106 return estate->es_epqTuple[rti - 1];
02107 }
02108
02109
02110
02111
02112
02113
02114 void
02115 EvalPlanQualFetchRowMarks(EPQState *epqstate)
02116 {
02117 ListCell *l;
02118
02119 Assert(epqstate->origslot != NULL);
02120
02121 foreach(l, epqstate->arowMarks)
02122 {
02123 ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(l);
02124 ExecRowMark *erm = aerm->rowmark;
02125 Datum datum;
02126 bool isNull;
02127 HeapTupleData tuple;
02128
02129 if (RowMarkRequiresRowShareLock(erm->markType))
02130 elog(ERROR, "EvalPlanQual doesn't support locking rowmarks");
02131
02132
02133 EvalPlanQualSetTuple(epqstate, erm->rti, NULL);
02134
02135 if (erm->relation)
02136 {
02137 Buffer buffer;
02138
02139 Assert(erm->markType == ROW_MARK_REFERENCE);
02140
02141
02142 if (erm->rti != erm->prti)
02143 {
02144 Oid tableoid;
02145
02146 datum = ExecGetJunkAttribute(epqstate->origslot,
02147 aerm->toidAttNo,
02148 &isNull);
02149
02150 if (isNull)
02151 continue;
02152 tableoid = DatumGetObjectId(datum);
02153
02154 if (tableoid != RelationGetRelid(erm->relation))
02155 {
02156
02157 continue;
02158 }
02159 }
02160
02161
02162 datum = ExecGetJunkAttribute(epqstate->origslot,
02163 aerm->ctidAttNo,
02164 &isNull);
02165
02166 if (isNull)
02167 continue;
02168 tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
02169
02170
02171 if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
02172 false, NULL))
02173 elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
02174
02175
02176 EvalPlanQualSetTuple(epqstate, erm->rti,
02177 heap_copytuple(&tuple));
02178 ReleaseBuffer(buffer);
02179 }
02180 else
02181 {
02182 HeapTupleHeader td;
02183
02184 Assert(erm->markType == ROW_MARK_COPY);
02185
02186
02187 datum = ExecGetJunkAttribute(epqstate->origslot,
02188 aerm->wholeAttNo,
02189 &isNull);
02190
02191 if (isNull)
02192 continue;
02193 td = DatumGetHeapTupleHeader(datum);
02194
02195
02196 tuple.t_len = HeapTupleHeaderGetDatumLength(td);
02197 ItemPointerSetInvalid(&(tuple.t_self));
02198 tuple.t_tableOid = InvalidOid;
02199 tuple.t_data = td;
02200
02201
02202 EvalPlanQualSetTuple(epqstate, erm->rti,
02203 heap_copytuple(&tuple));
02204 }
02205 }
02206 }
02207
02208
02209
02210
02211
02212
02213 TupleTableSlot *
02214 EvalPlanQualNext(EPQState *epqstate)
02215 {
02216 MemoryContext oldcontext;
02217 TupleTableSlot *slot;
02218
02219 oldcontext = MemoryContextSwitchTo(epqstate->estate->es_query_cxt);
02220 slot = ExecProcNode(epqstate->planstate);
02221 MemoryContextSwitchTo(oldcontext);
02222
02223 return slot;
02224 }
02225
02226
02227
02228
02229 void
02230 EvalPlanQualBegin(EPQState *epqstate, EState *parentestate)
02231 {
02232 EState *estate = epqstate->estate;
02233
02234 if (estate == NULL)
02235 {
02236
02237 EvalPlanQualStart(epqstate, parentestate, epqstate->plan);
02238 }
02239 else
02240 {
02241
02242
02243
02244 int rtsize = list_length(parentestate->es_range_table);
02245 PlanState *planstate = epqstate->planstate;
02246
02247 MemSet(estate->es_epqScanDone, 0, rtsize * sizeof(bool));
02248
02249
02250 if (parentestate->es_plannedstmt->nParamExec > 0)
02251 {
02252 int i = parentestate->es_plannedstmt->nParamExec;
02253
02254 while (--i >= 0)
02255 {
02256
02257 estate->es_param_exec_vals[i].value =
02258 parentestate->es_param_exec_vals[i].value;
02259 estate->es_param_exec_vals[i].isnull =
02260 parentestate->es_param_exec_vals[i].isnull;
02261 }
02262 }
02263
02264
02265
02266
02267
02268 planstate->chgParam = bms_add_member(planstate->chgParam,
02269 epqstate->epqParam);
02270 }
02271 }
02272
02273
02274
02275
02276
02277
02278
02279 static void
02280 EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
02281 {
02282 EState *estate;
02283 int rtsize;
02284 MemoryContext oldcontext;
02285 ListCell *l;
02286
02287 rtsize = list_length(parentestate->es_range_table);
02288
02289 epqstate->estate = estate = CreateExecutorState();
02290
02291 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
02292
02293
02294
02295
02296
02297
02298
02299 estate->es_direction = ForwardScanDirection;
02300 estate->es_snapshot = parentestate->es_snapshot;
02301 estate->es_crosscheck_snapshot = parentestate->es_crosscheck_snapshot;
02302 estate->es_range_table = parentestate->es_range_table;
02303 estate->es_plannedstmt = parentestate->es_plannedstmt;
02304 estate->es_junkFilter = parentestate->es_junkFilter;
02305 estate->es_output_cid = parentestate->es_output_cid;
02306 estate->es_result_relations = parentestate->es_result_relations;
02307 estate->es_num_result_relations = parentestate->es_num_result_relations;
02308 estate->es_result_relation_info = parentestate->es_result_relation_info;
02309
02310 estate->es_rowMarks = parentestate->es_rowMarks;
02311 estate->es_top_eflags = parentestate->es_top_eflags;
02312 estate->es_instrument = parentestate->es_instrument;
02313
02314
02315
02316
02317
02318
02319
02320
02321 estate->es_param_list_info = parentestate->es_param_list_info;
02322 if (parentestate->es_plannedstmt->nParamExec > 0)
02323 {
02324 int i = parentestate->es_plannedstmt->nParamExec;
02325
02326 estate->es_param_exec_vals = (ParamExecData *)
02327 palloc0(i * sizeof(ParamExecData));
02328 while (--i >= 0)
02329 {
02330
02331 estate->es_param_exec_vals[i].value =
02332 parentestate->es_param_exec_vals[i].value;
02333 estate->es_param_exec_vals[i].isnull =
02334 parentestate->es_param_exec_vals[i].isnull;
02335 }
02336 }
02337
02338
02339
02340
02341
02342
02343 estate->es_epqScanDone = (bool *) palloc0(rtsize * sizeof(bool));
02344 if (parentestate->es_epqTuple != NULL)
02345 {
02346 estate->es_epqTuple = parentestate->es_epqTuple;
02347 estate->es_epqTupleSet = parentestate->es_epqTupleSet;
02348 }
02349 else
02350 {
02351 estate->es_epqTuple = (HeapTuple *)
02352 palloc0(rtsize * sizeof(HeapTuple));
02353 estate->es_epqTupleSet = (bool *)
02354 palloc0(rtsize * sizeof(bool));
02355 }
02356
02357
02358
02359
02360 estate->es_tupleTable = NIL;
02361
02362
02363
02364
02365
02366
02367
02368
02369
02370 Assert(estate->es_subplanstates == NIL);
02371 foreach(l, parentestate->es_plannedstmt->subplans)
02372 {
02373 Plan *subplan = (Plan *) lfirst(l);
02374 PlanState *subplanstate;
02375
02376 subplanstate = ExecInitNode(subplan, estate, 0);
02377 estate->es_subplanstates = lappend(estate->es_subplanstates,
02378 subplanstate);
02379 }
02380
02381
02382
02383
02384
02385
02386 epqstate->planstate = ExecInitNode(planTree, estate, 0);
02387
02388 MemoryContextSwitchTo(oldcontext);
02389 }
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401 void
02402 EvalPlanQualEnd(EPQState *epqstate)
02403 {
02404 EState *estate = epqstate->estate;
02405 MemoryContext oldcontext;
02406 ListCell *l;
02407
02408 if (estate == NULL)
02409 return;
02410
02411 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
02412
02413 ExecEndNode(epqstate->planstate);
02414
02415 foreach(l, estate->es_subplanstates)
02416 {
02417 PlanState *subplanstate = (PlanState *) lfirst(l);
02418
02419 ExecEndNode(subplanstate);
02420 }
02421
02422
02423 ExecResetTupleTable(estate->es_tupleTable, false);
02424
02425
02426 foreach(l, estate->es_trig_target_relations)
02427 {
02428 ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
02429
02430
02431 ExecCloseIndices(resultRelInfo);
02432 heap_close(resultRelInfo->ri_RelationDesc, NoLock);
02433 }
02434
02435 MemoryContextSwitchTo(oldcontext);
02436
02437 FreeExecutorState(estate);
02438
02439
02440 epqstate->estate = NULL;
02441 epqstate->planstate = NULL;
02442 epqstate->origslot = NULL;
02443 }