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/xact.h"
00042 #include "commands/trigger.h"
00043 #include "executor/executor.h"
00044 #include "executor/nodeModifyTable.h"
00045 #include "foreign/fdwapi.h"
00046 #include "miscadmin.h"
00047 #include "nodes/nodeFuncs.h"
00048 #include "storage/bufmgr.h"
00049 #include "utils/builtins.h"
00050 #include "utils/memutils.h"
00051 #include "utils/rel.h"
00052 #include "utils/tqual.h"
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 static void
00068 ExecCheckPlanOutput(Relation resultRel, List *targetList)
00069 {
00070 TupleDesc resultDesc = RelationGetDescr(resultRel);
00071 int attno = 0;
00072 ListCell *lc;
00073
00074 foreach(lc, targetList)
00075 {
00076 TargetEntry *tle = (TargetEntry *) lfirst(lc);
00077 Form_pg_attribute attr;
00078
00079 if (tle->resjunk)
00080 continue;
00081
00082 if (attno >= resultDesc->natts)
00083 ereport(ERROR,
00084 (errcode(ERRCODE_DATATYPE_MISMATCH),
00085 errmsg("table row type and query-specified row type do not match"),
00086 errdetail("Query has too many columns.")));
00087 attr = resultDesc->attrs[attno++];
00088
00089 if (!attr->attisdropped)
00090 {
00091
00092 if (exprType((Node *) tle->expr) != attr->atttypid)
00093 ereport(ERROR,
00094 (errcode(ERRCODE_DATATYPE_MISMATCH),
00095 errmsg("table row type and query-specified row type do not match"),
00096 errdetail("Table has type %s at ordinal position %d, but query expects %s.",
00097 format_type_be(attr->atttypid),
00098 attno,
00099 format_type_be(exprType((Node *) tle->expr)))));
00100 }
00101 else
00102 {
00103
00104
00105
00106
00107
00108 if (!IsA(tle->expr, Const) ||
00109 !((Const *) tle->expr)->constisnull)
00110 ereport(ERROR,
00111 (errcode(ERRCODE_DATATYPE_MISMATCH),
00112 errmsg("table row type and query-specified row type do not match"),
00113 errdetail("Query provides a value for a dropped column at ordinal position %d.",
00114 attno)));
00115 }
00116 }
00117 if (attno != resultDesc->natts)
00118 ereport(ERROR,
00119 (errcode(ERRCODE_DATATYPE_MISMATCH),
00120 errmsg("table row type and query-specified row type do not match"),
00121 errdetail("Query has too few columns.")));
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 static TupleTableSlot *
00134 ExecProcessReturning(ProjectionInfo *projectReturning,
00135 TupleTableSlot *tupleSlot,
00136 TupleTableSlot *planSlot)
00137 {
00138 ExprContext *econtext = projectReturning->pi_exprContext;
00139
00140
00141
00142
00143
00144 ResetExprContext(econtext);
00145
00146
00147 econtext->ecxt_scantuple = tupleSlot;
00148 econtext->ecxt_outertuple = planSlot;
00149
00150
00151 return ExecProject(projectReturning, NULL);
00152 }
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 static TupleTableSlot *
00164 ExecInsert(TupleTableSlot *slot,
00165 TupleTableSlot *planSlot,
00166 EState *estate,
00167 bool canSetTag)
00168 {
00169 HeapTuple tuple;
00170 ResultRelInfo *resultRelInfo;
00171 Relation resultRelationDesc;
00172 Oid newId;
00173 List *recheckIndexes = NIL;
00174
00175
00176
00177
00178
00179 tuple = ExecMaterializeSlot(slot);
00180
00181
00182
00183
00184 resultRelInfo = estate->es_result_relation_info;
00185 resultRelationDesc = resultRelInfo->ri_RelationDesc;
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 if (resultRelationDesc->rd_rel->relhasoids)
00200 HeapTupleSetOid(tuple, InvalidOid);
00201
00202
00203 if (resultRelInfo->ri_TrigDesc &&
00204 resultRelInfo->ri_TrigDesc->trig_insert_before_row)
00205 {
00206 slot = ExecBRInsertTriggers(estate, resultRelInfo, slot);
00207
00208 if (slot == NULL)
00209 return NULL;
00210
00211
00212 tuple = ExecMaterializeSlot(slot);
00213 }
00214
00215
00216 if (resultRelInfo->ri_TrigDesc &&
00217 resultRelInfo->ri_TrigDesc->trig_insert_instead_row)
00218 {
00219 slot = ExecIRInsertTriggers(estate, resultRelInfo, slot);
00220
00221 if (slot == NULL)
00222 return NULL;
00223
00224
00225 tuple = ExecMaterializeSlot(slot);
00226
00227 newId = InvalidOid;
00228 }
00229 else if (resultRelInfo->ri_FdwRoutine)
00230 {
00231
00232
00233
00234 slot = resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate,
00235 resultRelInfo,
00236 slot,
00237 planSlot);
00238
00239 if (slot == NULL)
00240 return NULL;
00241
00242
00243 tuple = ExecMaterializeSlot(slot);
00244
00245 newId = InvalidOid;
00246 }
00247 else
00248 {
00249
00250
00251
00252 if (resultRelationDesc->rd_att->constr)
00253 ExecConstraints(resultRelInfo, slot, estate);
00254
00255
00256
00257
00258
00259
00260
00261 newId = heap_insert(resultRelationDesc, tuple,
00262 estate->es_output_cid, 0, NULL);
00263
00264
00265
00266
00267 if (resultRelInfo->ri_NumIndices > 0)
00268 recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
00269 estate);
00270 }
00271
00272 if (canSetTag)
00273 {
00274 (estate->es_processed)++;
00275 estate->es_lastoid = newId;
00276 setLastTid(&(tuple->t_self));
00277 }
00278
00279
00280 ExecARInsertTriggers(estate, resultRelInfo, tuple, recheckIndexes);
00281
00282 list_free(recheckIndexes);
00283
00284
00285 if (resultRelInfo->ri_projectReturning)
00286 return ExecProcessReturning(resultRelInfo->ri_projectReturning,
00287 slot, planSlot);
00288
00289 return NULL;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 static TupleTableSlot *
00309 ExecDelete(ItemPointer tupleid,
00310 HeapTupleHeader oldtuple,
00311 TupleTableSlot *planSlot,
00312 EPQState *epqstate,
00313 EState *estate,
00314 bool canSetTag)
00315 {
00316 ResultRelInfo *resultRelInfo;
00317 Relation resultRelationDesc;
00318 HTSU_Result result;
00319 HeapUpdateFailureData hufd;
00320 TupleTableSlot *slot = NULL;
00321
00322
00323
00324
00325 resultRelInfo = estate->es_result_relation_info;
00326 resultRelationDesc = resultRelInfo->ri_RelationDesc;
00327
00328
00329 if (resultRelInfo->ri_TrigDesc &&
00330 resultRelInfo->ri_TrigDesc->trig_delete_before_row)
00331 {
00332 bool dodelete;
00333
00334 dodelete = ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
00335 tupleid);
00336
00337 if (!dodelete)
00338 return NULL;
00339 }
00340
00341
00342 if (resultRelInfo->ri_TrigDesc &&
00343 resultRelInfo->ri_TrigDesc->trig_delete_instead_row)
00344 {
00345 HeapTupleData tuple;
00346 bool dodelete;
00347
00348 Assert(oldtuple != NULL);
00349 tuple.t_data = oldtuple;
00350 tuple.t_len = HeapTupleHeaderGetDatumLength(oldtuple);
00351 ItemPointerSetInvalid(&(tuple.t_self));
00352 tuple.t_tableOid = InvalidOid;
00353
00354 dodelete = ExecIRDeleteTriggers(estate, resultRelInfo, &tuple);
00355
00356 if (!dodelete)
00357 return NULL;
00358 }
00359 else if (resultRelInfo->ri_FdwRoutine)
00360 {
00361
00362
00363
00364
00365
00366
00367
00368 slot = estate->es_trig_tuple_slot;
00369 if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc))
00370 ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc));
00371
00372 slot = resultRelInfo->ri_FdwRoutine->ExecForeignDelete(estate,
00373 resultRelInfo,
00374 slot,
00375 planSlot);
00376
00377 if (slot == NULL)
00378 return NULL;
00379 }
00380 else
00381 {
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 ldelete:;
00392 result = heap_delete(resultRelationDesc, tupleid,
00393 estate->es_output_cid,
00394 estate->es_crosscheck_snapshot,
00395 true ,
00396 &hufd);
00397 switch (result)
00398 {
00399 case HeapTupleSelfUpdated:
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 if (hufd.cmax != estate->es_output_cid)
00425 ereport(ERROR,
00426 (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
00427 errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
00428 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
00429
00430
00431 return NULL;
00432
00433 case HeapTupleMayBeUpdated:
00434 break;
00435
00436 case HeapTupleUpdated:
00437 if (IsolationUsesXactSnapshot())
00438 ereport(ERROR,
00439 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
00440 errmsg("could not serialize access due to concurrent update")));
00441 if (!ItemPointerEquals(tupleid, &hufd.ctid))
00442 {
00443 TupleTableSlot *epqslot;
00444
00445 epqslot = EvalPlanQual(estate,
00446 epqstate,
00447 resultRelationDesc,
00448 resultRelInfo->ri_RangeTableIndex,
00449 LockTupleExclusive,
00450 &hufd.ctid,
00451 hufd.xmax);
00452 if (!TupIsNull(epqslot))
00453 {
00454 *tupleid = hufd.ctid;
00455 goto ldelete;
00456 }
00457 }
00458
00459 return NULL;
00460
00461 default:
00462 elog(ERROR, "unrecognized heap_delete status: %u", result);
00463 return NULL;
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 }
00475
00476 if (canSetTag)
00477 (estate->es_processed)++;
00478
00479
00480 ExecARDeleteTriggers(estate, resultRelInfo, tupleid);
00481
00482
00483 if (resultRelInfo->ri_projectReturning)
00484 {
00485
00486
00487
00488
00489 TupleTableSlot *rslot;
00490 HeapTupleData deltuple;
00491 Buffer delbuffer;
00492
00493 if (resultRelInfo->ri_FdwRoutine)
00494 {
00495
00496 Assert(!TupIsNull(slot));
00497 delbuffer = InvalidBuffer;
00498 }
00499 else
00500 {
00501 slot = estate->es_trig_tuple_slot;
00502 if (oldtuple != NULL)
00503 {
00504 deltuple.t_data = oldtuple;
00505 deltuple.t_len = HeapTupleHeaderGetDatumLength(oldtuple);
00506 ItemPointerSetInvalid(&(deltuple.t_self));
00507 deltuple.t_tableOid = InvalidOid;
00508 delbuffer = InvalidBuffer;
00509 }
00510 else
00511 {
00512 deltuple.t_self = *tupleid;
00513 if (!heap_fetch(resultRelationDesc, SnapshotAny,
00514 &deltuple, &delbuffer, false, NULL))
00515 elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING");
00516 }
00517
00518 if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc))
00519 ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc));
00520 ExecStoreTuple(&deltuple, slot, InvalidBuffer, false);
00521 }
00522
00523 rslot = ExecProcessReturning(resultRelInfo->ri_projectReturning,
00524 slot, planSlot);
00525
00526
00527
00528
00529
00530 ExecMaterializeSlot(rslot);
00531
00532 ExecClearTuple(slot);
00533 if (BufferIsValid(delbuffer))
00534 ReleaseBuffer(delbuffer);
00535
00536 return rslot;
00537 }
00538
00539 return NULL;
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 static TupleTableSlot *
00563 ExecUpdate(ItemPointer tupleid,
00564 HeapTupleHeader oldtuple,
00565 TupleTableSlot *slot,
00566 TupleTableSlot *planSlot,
00567 EPQState *epqstate,
00568 EState *estate,
00569 bool canSetTag)
00570 {
00571 HeapTuple tuple;
00572 ResultRelInfo *resultRelInfo;
00573 Relation resultRelationDesc;
00574 HTSU_Result result;
00575 HeapUpdateFailureData hufd;
00576 List *recheckIndexes = NIL;
00577
00578
00579
00580
00581 if (IsBootstrapProcessingMode())
00582 elog(ERROR, "cannot UPDATE during bootstrap");
00583
00584
00585
00586
00587
00588 tuple = ExecMaterializeSlot(slot);
00589
00590
00591
00592
00593 resultRelInfo = estate->es_result_relation_info;
00594 resultRelationDesc = resultRelInfo->ri_RelationDesc;
00595
00596
00597 if (resultRelInfo->ri_TrigDesc &&
00598 resultRelInfo->ri_TrigDesc->trig_update_before_row)
00599 {
00600 slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
00601 tupleid, slot);
00602
00603 if (slot == NULL)
00604 return NULL;
00605
00606
00607 tuple = ExecMaterializeSlot(slot);
00608 }
00609
00610
00611 if (resultRelInfo->ri_TrigDesc &&
00612 resultRelInfo->ri_TrigDesc->trig_update_instead_row)
00613 {
00614 HeapTupleData oldtup;
00615
00616 Assert(oldtuple != NULL);
00617 oldtup.t_data = oldtuple;
00618 oldtup.t_len = HeapTupleHeaderGetDatumLength(oldtuple);
00619 ItemPointerSetInvalid(&(oldtup.t_self));
00620 oldtup.t_tableOid = InvalidOid;
00621
00622 slot = ExecIRUpdateTriggers(estate, resultRelInfo,
00623 &oldtup, slot);
00624
00625 if (slot == NULL)
00626 return NULL;
00627
00628
00629 tuple = ExecMaterializeSlot(slot);
00630 }
00631 else if (resultRelInfo->ri_FdwRoutine)
00632 {
00633
00634
00635
00636 slot = resultRelInfo->ri_FdwRoutine->ExecForeignUpdate(estate,
00637 resultRelInfo,
00638 slot,
00639 planSlot);
00640
00641 if (slot == NULL)
00642 return NULL;
00643
00644
00645 tuple = ExecMaterializeSlot(slot);
00646 }
00647 else
00648 {
00649 LockTupleMode lockmode;
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 lreplace:;
00661 if (resultRelationDesc->rd_att->constr)
00662 ExecConstraints(resultRelInfo, slot, estate);
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 result = heap_update(resultRelationDesc, tupleid, tuple,
00674 estate->es_output_cid,
00675 estate->es_crosscheck_snapshot,
00676 true ,
00677 &hufd, &lockmode);
00678 switch (result)
00679 {
00680 case HeapTupleSelfUpdated:
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 if (hufd.cmax != estate->es_output_cid)
00705 ereport(ERROR,
00706 (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
00707 errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
00708 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
00709
00710
00711 return NULL;
00712
00713 case HeapTupleMayBeUpdated:
00714 break;
00715
00716 case HeapTupleUpdated:
00717 if (IsolationUsesXactSnapshot())
00718 ereport(ERROR,
00719 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
00720 errmsg("could not serialize access due to concurrent update")));
00721 if (!ItemPointerEquals(tupleid, &hufd.ctid))
00722 {
00723 TupleTableSlot *epqslot;
00724
00725 epqslot = EvalPlanQual(estate,
00726 epqstate,
00727 resultRelationDesc,
00728 resultRelInfo->ri_RangeTableIndex,
00729 lockmode,
00730 &hufd.ctid,
00731 hufd.xmax);
00732 if (!TupIsNull(epqslot))
00733 {
00734 *tupleid = hufd.ctid;
00735 slot = ExecFilterJunk(resultRelInfo->ri_junkFilter, epqslot);
00736 tuple = ExecMaterializeSlot(slot);
00737 goto lreplace;
00738 }
00739 }
00740
00741 return NULL;
00742
00743 default:
00744 elog(ERROR, "unrecognized heap_update status: %u", result);
00745 return NULL;
00746 }
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764 if (resultRelInfo->ri_NumIndices > 0 && !HeapTupleIsHeapOnly(tuple))
00765 recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
00766 estate);
00767 }
00768
00769 if (canSetTag)
00770 (estate->es_processed)++;
00771
00772
00773 ExecARUpdateTriggers(estate, resultRelInfo, tupleid, tuple,
00774 recheckIndexes);
00775
00776 list_free(recheckIndexes);
00777
00778
00779 if (resultRelInfo->ri_projectReturning)
00780 return ExecProcessReturning(resultRelInfo->ri_projectReturning,
00781 slot, planSlot);
00782
00783 return NULL;
00784 }
00785
00786
00787
00788
00789
00790 static void
00791 fireBSTriggers(ModifyTableState *node)
00792 {
00793 switch (node->operation)
00794 {
00795 case CMD_INSERT:
00796 ExecBSInsertTriggers(node->ps.state, node->resultRelInfo);
00797 break;
00798 case CMD_UPDATE:
00799 ExecBSUpdateTriggers(node->ps.state, node->resultRelInfo);
00800 break;
00801 case CMD_DELETE:
00802 ExecBSDeleteTriggers(node->ps.state, node->resultRelInfo);
00803 break;
00804 default:
00805 elog(ERROR, "unknown operation");
00806 break;
00807 }
00808 }
00809
00810
00811
00812
00813 static void
00814 fireASTriggers(ModifyTableState *node)
00815 {
00816 switch (node->operation)
00817 {
00818 case CMD_INSERT:
00819 ExecASInsertTriggers(node->ps.state, node->resultRelInfo);
00820 break;
00821 case CMD_UPDATE:
00822 ExecASUpdateTriggers(node->ps.state, node->resultRelInfo);
00823 break;
00824 case CMD_DELETE:
00825 ExecASDeleteTriggers(node->ps.state, node->resultRelInfo);
00826 break;
00827 default:
00828 elog(ERROR, "unknown operation");
00829 break;
00830 }
00831 }
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841 TupleTableSlot *
00842 ExecModifyTable(ModifyTableState *node)
00843 {
00844 EState *estate = node->ps.state;
00845 CmdType operation = node->operation;
00846 ResultRelInfo *saved_resultRelInfo;
00847 ResultRelInfo *resultRelInfo;
00848 PlanState *subplanstate;
00849 JunkFilter *junkfilter;
00850 TupleTableSlot *slot;
00851 TupleTableSlot *planSlot;
00852 ItemPointer tupleid = NULL;
00853 ItemPointerData tuple_ctid;
00854 HeapTupleHeader oldtuple = NULL;
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865 if (estate->es_epqTuple != NULL)
00866 elog(ERROR, "ModifyTable should not be called during EvalPlanQual");
00867
00868
00869
00870
00871
00872
00873
00874 if (node->mt_done)
00875 return NULL;
00876
00877
00878
00879
00880 if (node->fireBSTriggers)
00881 {
00882 fireBSTriggers(node);
00883 node->fireBSTriggers = false;
00884 }
00885
00886
00887 resultRelInfo = node->resultRelInfo + node->mt_whichplan;
00888 subplanstate = node->mt_plans[node->mt_whichplan];
00889 junkfilter = resultRelInfo->ri_junkFilter;
00890
00891
00892
00893
00894
00895
00896
00897
00898 saved_resultRelInfo = estate->es_result_relation_info;
00899
00900 estate->es_result_relation_info = resultRelInfo;
00901
00902
00903
00904
00905
00906 for (;;)
00907 {
00908
00909
00910
00911
00912
00913
00914 ResetPerTupleExprContext(estate);
00915
00916 planSlot = ExecProcNode(subplanstate);
00917
00918 if (TupIsNull(planSlot))
00919 {
00920
00921 node->mt_whichplan++;
00922 if (node->mt_whichplan < node->mt_nplans)
00923 {
00924 resultRelInfo++;
00925 subplanstate = node->mt_plans[node->mt_whichplan];
00926 junkfilter = resultRelInfo->ri_junkFilter;
00927 estate->es_result_relation_info = resultRelInfo;
00928 EvalPlanQualSetPlan(&node->mt_epqstate, subplanstate->plan,
00929 node->mt_arowmarks[node->mt_whichplan]);
00930 continue;
00931 }
00932 else
00933 break;
00934 }
00935
00936 EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
00937 slot = planSlot;
00938
00939 if (junkfilter != NULL)
00940 {
00941
00942
00943
00944 if (operation == CMD_UPDATE || operation == CMD_DELETE)
00945 {
00946 char relkind;
00947 Datum datum;
00948 bool isNull;
00949
00950 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
00951 if (relkind == RELKIND_RELATION)
00952 {
00953 datum = ExecGetJunkAttribute(slot,
00954 junkfilter->jf_junkAttNo,
00955 &isNull);
00956
00957 if (isNull)
00958 elog(ERROR, "ctid is NULL");
00959
00960 tupleid = (ItemPointer) DatumGetPointer(datum);
00961 tuple_ctid = *tupleid;
00962
00963 tupleid = &tuple_ctid;
00964 }
00965 else if (relkind == RELKIND_FOREIGN_TABLE)
00966 {
00967
00968 }
00969 else
00970 {
00971 datum = ExecGetJunkAttribute(slot,
00972 junkfilter->jf_junkAttNo,
00973 &isNull);
00974
00975 if (isNull)
00976 elog(ERROR, "wholerow is NULL");
00977
00978 oldtuple = DatumGetHeapTupleHeader(datum);
00979 }
00980 }
00981
00982
00983
00984
00985 if (operation != CMD_DELETE)
00986 slot = ExecFilterJunk(junkfilter, slot);
00987 }
00988
00989 switch (operation)
00990 {
00991 case CMD_INSERT:
00992 slot = ExecInsert(slot, planSlot, estate, node->canSetTag);
00993 break;
00994 case CMD_UPDATE:
00995 slot = ExecUpdate(tupleid, oldtuple, slot, planSlot,
00996 &node->mt_epqstate, estate, node->canSetTag);
00997 break;
00998 case CMD_DELETE:
00999 slot = ExecDelete(tupleid, oldtuple, planSlot,
01000 &node->mt_epqstate, estate, node->canSetTag);
01001 break;
01002 default:
01003 elog(ERROR, "unknown operation");
01004 break;
01005 }
01006
01007
01008
01009
01010
01011 if (slot)
01012 {
01013 estate->es_result_relation_info = saved_resultRelInfo;
01014 return slot;
01015 }
01016 }
01017
01018
01019 estate->es_result_relation_info = saved_resultRelInfo;
01020
01021
01022
01023
01024 fireASTriggers(node);
01025
01026 node->mt_done = true;
01027
01028 return NULL;
01029 }
01030
01031
01032
01033
01034
01035 ModifyTableState *
01036 ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
01037 {
01038 ModifyTableState *mtstate;
01039 CmdType operation = node->operation;
01040 int nplans = list_length(node->plans);
01041 ResultRelInfo *saved_resultRelInfo;
01042 ResultRelInfo *resultRelInfo;
01043 TupleDesc tupDesc;
01044 Plan *subplan;
01045 ListCell *l;
01046 int i;
01047
01048
01049 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
01050
01051
01052
01053
01054 mtstate = makeNode(ModifyTableState);
01055 mtstate->ps.plan = (Plan *) node;
01056 mtstate->ps.state = estate;
01057 mtstate->ps.targetlist = NIL;
01058
01059 mtstate->operation = operation;
01060 mtstate->canSetTag = node->canSetTag;
01061 mtstate->mt_done = false;
01062
01063 mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
01064 mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
01065 mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
01066 mtstate->mt_nplans = nplans;
01067
01068
01069 EvalPlanQualInit(&mtstate->mt_epqstate, estate, NULL, NIL, node->epqParam);
01070 mtstate->fireBSTriggers = true;
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080 saved_resultRelInfo = estate->es_result_relation_info;
01081
01082 resultRelInfo = mtstate->resultRelInfo;
01083 i = 0;
01084 foreach(l, node->plans)
01085 {
01086 subplan = (Plan *) lfirst(l);
01087
01088
01089
01090
01091 CheckValidResultRel(resultRelInfo->ri_RelationDesc, operation);
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102 if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
01103 operation != CMD_DELETE &&
01104 resultRelInfo->ri_IndexRelationDescs == NULL)
01105 ExecOpenIndices(resultRelInfo);
01106
01107
01108 estate->es_result_relation_info = resultRelInfo;
01109 mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
01110
01111
01112 if (resultRelInfo->ri_FdwRoutine != NULL &&
01113 resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
01114 {
01115 List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
01116
01117 resultRelInfo->ri_FdwRoutine->BeginForeignModify(mtstate,
01118 resultRelInfo,
01119 fdw_private,
01120 i,
01121 eflags);
01122 }
01123
01124 resultRelInfo++;
01125 i++;
01126 }
01127
01128 estate->es_result_relation_info = saved_resultRelInfo;
01129
01130
01131
01132
01133 if (node->returningLists)
01134 {
01135 TupleTableSlot *slot;
01136 ExprContext *econtext;
01137
01138
01139
01140
01141
01142 tupDesc = ExecTypeFromTL((List *) linitial(node->returningLists),
01143 false);
01144
01145
01146 ExecInitResultTupleSlot(estate, &mtstate->ps);
01147 ExecAssignResultType(&mtstate->ps, tupDesc);
01148 slot = mtstate->ps.ps_ResultTupleSlot;
01149
01150
01151 econtext = CreateExprContext(estate);
01152 mtstate->ps.ps_ExprContext = econtext;
01153
01154
01155
01156
01157 resultRelInfo = mtstate->resultRelInfo;
01158 foreach(l, node->returningLists)
01159 {
01160 List *rlist = (List *) lfirst(l);
01161 List *rliststate;
01162
01163 rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
01164 resultRelInfo->ri_projectReturning =
01165 ExecBuildProjectionInfo(rliststate, econtext, slot,
01166 resultRelInfo->ri_RelationDesc->rd_att);
01167 resultRelInfo++;
01168 }
01169 }
01170 else
01171 {
01172
01173
01174
01175
01176 tupDesc = ExecTypeFromTL(NIL, false);
01177 ExecInitResultTupleSlot(estate, &mtstate->ps);
01178 ExecAssignResultType(&mtstate->ps, tupDesc);
01179
01180 mtstate->ps.ps_ExprContext = NULL;
01181 }
01182
01183
01184
01185
01186
01187
01188
01189 foreach(l, node->rowMarks)
01190 {
01191 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
01192 ExecRowMark *erm;
01193
01194 Assert(IsA(rc, PlanRowMark));
01195
01196
01197 if (rc->isParent)
01198 continue;
01199
01200
01201 erm = ExecFindRowMark(estate, rc->rti);
01202
01203
01204 for (i = 0; i < nplans; i++)
01205 {
01206 ExecAuxRowMark *aerm;
01207
01208 subplan = mtstate->mt_plans[i]->plan;
01209 aerm = ExecBuildAuxRowMark(erm, subplan->targetlist);
01210 mtstate->mt_arowmarks[i] = lappend(mtstate->mt_arowmarks[i], aerm);
01211 }
01212 }
01213
01214
01215 mtstate->mt_whichplan = 0;
01216 subplan = (Plan *) linitial(node->plans);
01217 EvalPlanQualSetPlan(&mtstate->mt_epqstate, subplan,
01218 mtstate->mt_arowmarks[0]);
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233 {
01234 bool junk_filter_needed = false;
01235
01236 switch (operation)
01237 {
01238 case CMD_INSERT:
01239 foreach(l, subplan->targetlist)
01240 {
01241 TargetEntry *tle = (TargetEntry *) lfirst(l);
01242
01243 if (tle->resjunk)
01244 {
01245 junk_filter_needed = true;
01246 break;
01247 }
01248 }
01249 break;
01250 case CMD_UPDATE:
01251 case CMD_DELETE:
01252 junk_filter_needed = true;
01253 break;
01254 default:
01255 elog(ERROR, "unknown operation");
01256 break;
01257 }
01258
01259 if (junk_filter_needed)
01260 {
01261 resultRelInfo = mtstate->resultRelInfo;
01262 for (i = 0; i < nplans; i++)
01263 {
01264 JunkFilter *j;
01265
01266 subplan = mtstate->mt_plans[i]->plan;
01267 if (operation == CMD_INSERT || operation == CMD_UPDATE)
01268 ExecCheckPlanOutput(resultRelInfo->ri_RelationDesc,
01269 subplan->targetlist);
01270
01271 j = ExecInitJunkFilter(subplan->targetlist,
01272 resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
01273 ExecInitExtraTupleSlot(estate));
01274
01275 if (operation == CMD_UPDATE || operation == CMD_DELETE)
01276 {
01277
01278 char relkind;
01279
01280 relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
01281 if (relkind == RELKIND_RELATION)
01282 {
01283 j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
01284 if (!AttributeNumberIsValid(j->jf_junkAttNo))
01285 elog(ERROR, "could not find junk ctid column");
01286 }
01287 else if (relkind == RELKIND_FOREIGN_TABLE)
01288 {
01289
01290 }
01291 else
01292 {
01293 j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
01294 if (!AttributeNumberIsValid(j->jf_junkAttNo))
01295 elog(ERROR, "could not find junk wholerow column");
01296 }
01297 }
01298
01299 resultRelInfo->ri_junkFilter = j;
01300 resultRelInfo++;
01301 }
01302 }
01303 else
01304 {
01305 if (operation == CMD_INSERT)
01306 ExecCheckPlanOutput(mtstate->resultRelInfo->ri_RelationDesc,
01307 subplan->targetlist);
01308 }
01309 }
01310
01311
01312
01313
01314
01315
01316 if (estate->es_trig_tuple_slot == NULL)
01317 estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328 if (!mtstate->canSetTag)
01329 estate->es_auxmodifytables = lcons(mtstate,
01330 estate->es_auxmodifytables);
01331
01332 return mtstate;
01333 }
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343 void
01344 ExecEndModifyTable(ModifyTableState *node)
01345 {
01346 int i;
01347
01348
01349
01350
01351 for (i = 0; i < node->mt_nplans; i++)
01352 {
01353 ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
01354
01355 if (resultRelInfo->ri_FdwRoutine != NULL &&
01356 resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
01357 resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
01358 resultRelInfo);
01359 }
01360
01361
01362
01363
01364 ExecFreeExprContext(&node->ps);
01365
01366
01367
01368
01369 ExecClearTuple(node->ps.ps_ResultTupleSlot);
01370
01371
01372
01373
01374 EvalPlanQualEnd(&node->mt_epqstate);
01375
01376
01377
01378
01379 for (i = 0; i < node->mt_nplans; i++)
01380 ExecEndNode(node->mt_plans[i]);
01381 }
01382
01383 void
01384 ExecReScanModifyTable(ModifyTableState *node)
01385 {
01386
01387
01388
01389
01390 elog(ERROR, "ExecReScanModifyTable is not implemented");
01391 }