1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-30 21:42:05 +03:00

Modified files for MERGE

This commit is contained in:
Simon Riggs
2018-04-02 21:12:47 +01:00
parent e6597dc353
commit 354f13855e
82 changed files with 2570 additions and 165 deletions

View File

@ -946,6 +946,9 @@ ExplainNode(PlanState *planstate, List *ancestors,
case CMD_DELETE:
pname = operation = "Delete";
break;
case CMD_MERGE:
pname = operation = "Merge";
break;
default:
pname = "???";
break;
@ -3007,6 +3010,10 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
operation = "Delete";
foperation = "Foreign Delete";
break;
case CMD_MERGE:
operation = "Merge";
foperation = "Foreign Merge";
break;
default:
operation = "???";
foperation = "Foreign ???";
@ -3129,6 +3136,32 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
other_path, 0, es);
}
}
else if (node->operation == CMD_MERGE)
{
/* EXPLAIN ANALYZE display of actual outcome for each tuple proposed */
if (es->analyze && mtstate->ps.instrument)
{
double total;
double insert_path;
double update_path;
double delete_path;
double skipped_path;
InstrEndLoop(mtstate->mt_plans[0]->instrument);
/* count the number of source rows */
total = mtstate->mt_plans[0]->instrument->ntuples;
insert_path = mtstate->ps.instrument->nfiltered1;
update_path = mtstate->ps.instrument->nfiltered2;
delete_path = mtstate->ps.instrument->nfiltered3;
skipped_path = total - insert_path - update_path - delete_path;
ExplainPropertyFloat("Tuples Inserted", NULL, insert_path, 0, es);
ExplainPropertyFloat("Tuples Updated", NULL, update_path, 0, es);
ExplainPropertyFloat("Tuples Deleted", NULL, delete_path, 0, es);
ExplainPropertyFloat("Tuples Skipped", NULL, skipped_path, 0, es);
}
}
if (labeltargets)
ExplainCloseGroup("Target Tables", "Target Tables", false, es);

View File

@ -151,6 +151,7 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString,
case CMD_INSERT:
case CMD_UPDATE:
case CMD_DELETE:
case CMD_MERGE:
/* OK */
break;
default:

View File

@ -85,7 +85,8 @@ static HeapTuple GetTupleForTrigger(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tid,
LockTupleMode lockmode,
TupleTableSlot **newSlot);
TupleTableSlot **newSlot,
HeapUpdateFailureData *hufdp);
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
Trigger *trigger, TriggerEvent event,
Bitmapset *modifiedCols,
@ -2729,7 +2730,8 @@ bool
ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
ResultRelInfo *relinfo,
ItemPointer tupleid,
HeapTuple fdw_trigtuple)
HeapTuple fdw_trigtuple,
HeapUpdateFailureData *hufdp)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
bool result = true;
@ -2743,7 +2745,7 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
if (fdw_trigtuple == NULL)
{
trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
LockTupleExclusive, &newSlot);
LockTupleExclusive, &newSlot, hufdp);
if (trigtuple == NULL)
return false;
}
@ -2814,6 +2816,7 @@ ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
relinfo,
tupleid,
LockTupleExclusive,
NULL,
NULL);
else
trigtuple = fdw_trigtuple;
@ -2951,7 +2954,8 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
ResultRelInfo *relinfo,
ItemPointer tupleid,
HeapTuple fdw_trigtuple,
TupleTableSlot *slot)
TupleTableSlot *slot,
HeapUpdateFailureData *hufdp)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
HeapTuple slottuple = ExecMaterializeSlot(slot);
@ -2972,7 +2976,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
{
/* get a copy of the on-disk tuple we are planning to update */
trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
lockmode, &newSlot);
lockmode, &newSlot, hufdp);
if (trigtuple == NULL)
return NULL; /* cancel the update action */
}
@ -3092,6 +3096,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
relinfo,
tupleid,
LockTupleExclusive,
NULL,
NULL);
else
trigtuple = fdw_trigtuple;
@ -3240,7 +3245,8 @@ GetTupleForTrigger(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tid,
LockTupleMode lockmode,
TupleTableSlot **newSlot)
TupleTableSlot **newSlot,
HeapUpdateFailureData *hufdp)
{
Relation relation = relinfo->ri_RelationDesc;
HeapTupleData tuple;
@ -3266,6 +3272,11 @@ ltrmark:;
estate->es_output_cid,
lockmode, LockWaitBlock,
false, &buffer, &hufd);
/* Let the caller know about failure reason, if any. */
if (hufdp)
*hufdp = hufd;
switch (test)
{
case HeapTupleSelfUpdated:
@ -3302,10 +3313,17 @@ ltrmark:;
/* it was updated, so look at the updated version */
TupleTableSlot *epqslot;
/*
* If we're running MERGE then we must install the
* new tuple in the slot of the underlying join query and
* not the result relation itself. If the join does not
* yield any tuple, the caller will take the necessary
* action.
*/
epqslot = EvalPlanQual(estate,
epqstate,
relation,
relinfo->ri_RangeTableIndex,
GetEPQRangeTableIndex(relinfo),
lockmode,
&hufd.ctid,
hufd.xmax);
@ -3828,8 +3846,14 @@ struct AfterTriggersTableData
bool before_trig_done; /* did we already queue BS triggers? */
bool after_trig_done; /* did we already queue AS triggers? */
AfterTriggerEventList after_trig_events; /* if so, saved list pointer */
Tuplestorestate *old_tuplestore; /* "old" transition table, if any */
Tuplestorestate *new_tuplestore; /* "new" transition table, if any */
/* "old" transition table for UPDATE, if any */
Tuplestorestate *old_upd_tuplestore;
/* "new" transition table for UPDATE, if any */
Tuplestorestate *new_upd_tuplestore;
/* "old" transition table for DELETE, if any */
Tuplestorestate *old_del_tuplestore;
/* "new" transition table INSERT, if any */
Tuplestorestate *new_ins_tuplestore;
};
static AfterTriggersData afterTriggers;
@ -4296,13 +4320,19 @@ AfterTriggerExecute(AfterTriggerEvent event,
{
if (LocTriggerData.tg_trigger->tgoldtable)
{
LocTriggerData.tg_oldtable = evtshared->ats_table->old_tuplestore;
if (TRIGGER_FIRED_BY_UPDATE(evtshared->ats_event))
LocTriggerData.tg_oldtable = evtshared->ats_table->old_upd_tuplestore;
else
LocTriggerData.tg_oldtable = evtshared->ats_table->old_del_tuplestore;
evtshared->ats_table->closed = true;
}
if (LocTriggerData.tg_trigger->tgnewtable)
{
LocTriggerData.tg_newtable = evtshared->ats_table->new_tuplestore;
if (TRIGGER_FIRED_BY_INSERT(evtshared->ats_event))
LocTriggerData.tg_newtable = evtshared->ats_table->new_ins_tuplestore;
else
LocTriggerData.tg_newtable = evtshared->ats_table->new_upd_tuplestore;
evtshared->ats_table->closed = true;
}
}
@ -4637,8 +4667,10 @@ TransitionCaptureState *
MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
{
TransitionCaptureState *state;
bool need_old,
need_new;
bool need_old_upd,
need_new_upd,
need_old_del,
need_new_ins;
AfterTriggersTableData *table;
MemoryContext oldcxt;
ResourceOwner saveResourceOwner;
@ -4650,23 +4682,31 @@ MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
switch (cmdType)
{
case CMD_INSERT:
need_old = false;
need_new = trigdesc->trig_insert_new_table;
need_old_upd = need_old_del = need_new_upd = false;
need_new_ins = trigdesc->trig_insert_new_table;
break;
case CMD_UPDATE:
need_old = trigdesc->trig_update_old_table;
need_new = trigdesc->trig_update_new_table;
need_old_upd = trigdesc->trig_update_old_table;
need_new_upd = trigdesc->trig_update_new_table;
need_old_del = need_new_ins = false;
break;
case CMD_DELETE:
need_old = trigdesc->trig_delete_old_table;
need_new = false;
need_old_del = trigdesc->trig_delete_old_table;
need_old_upd = need_new_upd = need_new_ins = false;
break;
case CMD_MERGE:
need_old_upd = trigdesc->trig_update_old_table;
need_new_upd = trigdesc->trig_update_new_table;
need_old_del = trigdesc->trig_delete_old_table;
need_new_ins = trigdesc->trig_insert_new_table;
break;
default:
elog(ERROR, "unexpected CmdType: %d", (int) cmdType);
need_old = need_new = false; /* keep compiler quiet */
/* keep compiler quiet */
need_old_upd = need_new_upd = need_old_del = need_new_ins = false;
break;
}
if (!need_old && !need_new)
if (!need_old_upd && !need_new_upd && !need_new_ins && !need_old_del)
return NULL;
/* Check state, like AfterTriggerSaveEvent. */
@ -4696,10 +4736,14 @@ MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = CurTransactionResourceOwner;
if (need_old && table->old_tuplestore == NULL)
table->old_tuplestore = tuplestore_begin_heap(false, false, work_mem);
if (need_new && table->new_tuplestore == NULL)
table->new_tuplestore = tuplestore_begin_heap(false, false, work_mem);
if (need_old_upd && table->old_upd_tuplestore == NULL)
table->old_upd_tuplestore = tuplestore_begin_heap(false, false, work_mem);
if (need_new_upd && table->new_upd_tuplestore == NULL)
table->new_upd_tuplestore = tuplestore_begin_heap(false, false, work_mem);
if (need_old_del && table->old_del_tuplestore == NULL)
table->old_del_tuplestore = tuplestore_begin_heap(false, false, work_mem);
if (need_new_ins && table->new_ins_tuplestore == NULL)
table->new_ins_tuplestore = tuplestore_begin_heap(false, false, work_mem);
CurrentResourceOwner = saveResourceOwner;
MemoryContextSwitchTo(oldcxt);
@ -4888,12 +4932,20 @@ AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
{
AfterTriggersTableData *table = (AfterTriggersTableData *) lfirst(lc);
ts = table->old_tuplestore;
table->old_tuplestore = NULL;
ts = table->old_upd_tuplestore;
table->old_upd_tuplestore = NULL;
if (ts)
tuplestore_end(ts);
ts = table->new_tuplestore;
table->new_tuplestore = NULL;
ts = table->new_upd_tuplestore;
table->new_upd_tuplestore = NULL;
if (ts)
tuplestore_end(ts);
ts = table->old_del_tuplestore;
table->old_del_tuplestore = NULL;
if (ts)
tuplestore_end(ts);
ts = table->new_ins_tuplestore;
table->new_ins_tuplestore = NULL;
if (ts)
tuplestore_end(ts);
}
@ -5744,12 +5796,28 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
newtup == NULL));
if (oldtup != NULL &&
((event == TRIGGER_EVENT_DELETE && delete_old_table) ||
(event == TRIGGER_EVENT_UPDATE && update_old_table)))
(event == TRIGGER_EVENT_DELETE && delete_old_table))
{
Tuplestorestate *old_tuplestore;
old_tuplestore = transition_capture->tcs_private->old_tuplestore;
old_tuplestore = transition_capture->tcs_private->old_del_tuplestore;
if (map != NULL)
{
HeapTuple converted = do_convert_tuple(oldtup, map);
tuplestore_puttuple(old_tuplestore, converted);
pfree(converted);
}
else
tuplestore_puttuple(old_tuplestore, oldtup);
}
if (oldtup != NULL &&
(event == TRIGGER_EVENT_UPDATE && update_old_table))
{
Tuplestorestate *old_tuplestore;
old_tuplestore = transition_capture->tcs_private->old_upd_tuplestore;
if (map != NULL)
{
@ -5762,12 +5830,30 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
tuplestore_puttuple(old_tuplestore, oldtup);
}
if (newtup != NULL &&
((event == TRIGGER_EVENT_INSERT && insert_new_table) ||
(event == TRIGGER_EVENT_UPDATE && update_new_table)))
(event == TRIGGER_EVENT_INSERT && insert_new_table))
{
Tuplestorestate *new_tuplestore;
new_tuplestore = transition_capture->tcs_private->new_tuplestore;
new_tuplestore = transition_capture->tcs_private->new_ins_tuplestore;
if (original_insert_tuple != NULL)
tuplestore_puttuple(new_tuplestore, original_insert_tuple);
else if (map != NULL)
{
HeapTuple converted = do_convert_tuple(newtup, map);
tuplestore_puttuple(new_tuplestore, converted);
pfree(converted);
}
else
tuplestore_puttuple(new_tuplestore, newtup);
}
if (newtup != NULL &&
(event == TRIGGER_EVENT_UPDATE && update_new_table))
{
Tuplestorestate *new_tuplestore;
new_tuplestore = transition_capture->tcs_private->new_upd_tuplestore;
if (original_insert_tuple != NULL)
tuplestore_puttuple(new_tuplestore, original_insert_tuple);