blob: 3094a62d89730524e7c58e02631b23432c53853c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*-------------------------------------------------------------------------
*
* nodeSplitUpdate.c
* Implementation of nodeSplitUpdate.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "miscadmin.h"
#include "cdb/cdbpartition.h"
#include "commands/tablecmds.h"
#include "executor/execDML.h"
#include "executor/instrument.h"
#include "executor/nodeSplitUpdate.h"
#include "utils/memutils.h"
/* Splits an update tuple into a DELETE/INSERT tuples. */
void
SplitTupleTableSlot(List *targetList, SplitUpdate *plannode, SplitUpdateState *node, Datum *values, bool *nulls);
/* Number of slots used by SplitUpdate node */
#define SPLITUPDATE_NSLOTS 3
/* Memory used by node */
#define SPLITUPDATE_MEM 1
/*
* Estimated Memory Usage of Split DML Node.
* */
void
ExecSplitUpdateExplainEnd(PlanState *planstate, struct StringInfoData *buf)
{
/* Add memory size of context */
planstate->instrument->execmemused += SPLITUPDATE_MEM;
}
/* Split TupleTableSlot into a DELETE and INSERT TupleTableSlot */
void
SplitTupleTableSlot(List *targetList, SplitUpdate *plannode, SplitUpdateState *node, Datum *values, bool *nulls)
{
ListCell *element = NULL;
ListCell *deleteAtt = plannode->deleteColIdx->head;
ListCell *insertAtt = plannode->insertColIdx->head;
Datum *delete_values = slot_get_values(node->deleteTuple);
bool *delete_nulls = slot_get_isnull(node->deleteTuple);
Datum *insert_values = slot_get_values(node->insertTuple);
bool *insert_nulls = slot_get_isnull(node->insertTuple);
/* Iterate through new TargetList and match old and new values. The action is also added in this containsTuple. */
foreach (element, targetList)
{
TargetEntry *tle = lfirst(element);
int resno = tle->resno-1;
if (IsA(tle->expr, DMLActionExpr))
{
/* Set the corresponding action to the new tuples. */
delete_values[resno] = Int32GetDatum((int)DML_DELETE);
delete_nulls[resno] = false;
insert_values[resno] = Int32GetDatum((int)DML_INSERT);
insert_nulls[resno] = false;
}
else if (((int)tle->resno) < plannode->ctidColIdx)
{
/* Old and new values */
delete_values[resno] = values[deleteAtt->data.int_value-1];
delete_nulls[resno] = nulls[deleteAtt->data.int_value-1];
insert_values[resno] = values[insertAtt->data.int_value-1];
insert_nulls[resno] = nulls[insertAtt->data.int_value-1];
deleteAtt = deleteAtt->next;
insertAtt = insertAtt->next;
}
else
{
/* `Resjunk' values */
delete_values[resno] = values[((Var *)tle->expr)->varattno-1];
delete_nulls[resno] = nulls[((Var *)tle->expr)->varattno-1];
insert_values[resno] = values[((Var *)tle->expr)->varattno-1];
insert_nulls[resno] = nulls[((Var *)tle->expr)->varattno-1];
}
}
}
/**
* Splits every TupleTableSlot into two TupleTableSlots: DELETE and INSERT.
*/
TupleTableSlot*
ExecSplitUpdate(SplitUpdateState *node)
{
PlanState *outerNode = outerPlanState(node);
SplitUpdate *plannode = (SplitUpdate *) node->ps.plan;
TupleTableSlot *slot = NULL;
TupleTableSlot *result = NULL;
Assert(outerNode != NULL);
/* Returns INSERT TupleTableSlot. */
if (!node->processInsert)
{
result = node->insertTuple;
node->processInsert = true;
}
else
{
/* Creates both TupleTableSlots. Returns DELETE TupleTableSlots.*/
slot = ExecProcNode(outerNode);
if (TupIsNull(slot))
{
return NULL;
}
/* `Split' update into delete and insert */
slot_getallattrs(slot);
Datum *values = slot_get_values(slot);
bool *nulls = slot_get_isnull(slot);
ExecStoreAllNullTuple(node->deleteTuple);
ExecStoreAllNullTuple(node->insertTuple);
SplitTupleTableSlot(plannode->plan.targetlist, plannode, node, values, nulls);
result = node->deleteTuple;
node->processInsert = false;
}
return result;
}
/*
* Init SplitUpdate Node. A memory context is created to hold Split Tuples.
* */
SplitUpdateState*
ExecInitSplitUpdate(SplitUpdate *node, EState *estate, int eflags)
{
/* Check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK | EXEC_FLAG_REWIND)));
SplitUpdateState *splitupdatestate;
splitupdatestate = makeNode(SplitUpdateState);
splitupdatestate->ps.plan = (Plan *)node;
splitupdatestate->ps.state = estate;
splitupdatestate->processInsert = true;
/*
* then initialize outer plan
*/
Plan *outerPlan = outerPlan(node);
outerPlanState(splitupdatestate) = ExecInitNode(outerPlan, estate, eflags);
ExecInitResultTupleSlot(estate, &splitupdatestate->ps);
splitupdatestate->insertTuple = ExecInitExtraTupleSlot(estate);
splitupdatestate->deleteTuple = ExecInitExtraTupleSlot(estate);
/* New TupleDescriptor for output TupleTableSlots (old_values + new_values, ctid, gp_segment, action).*/
TupleDesc tupDesc = ExecTypeFromTL(node->plan.targetlist, false);
ExecSetSlotDescriptor(splitupdatestate->insertTuple, tupDesc);
ExecSetSlotDescriptor(splitupdatestate->deleteTuple, tupDesc);
/*
* DML nodes do not project.
*/
ExecAssignResultTypeFromTL(&splitupdatestate->ps);
ExecAssignProjectionInfo(&splitupdatestate->ps, NULL);
if (estate->es_instrument)
{
splitupdatestate->ps.cdbexplainbuf = makeStringInfo();
/* Request a callback at end of query. */
splitupdatestate->ps.cdbexplainfun = ExecSplitUpdateExplainEnd;
}
initGpmonPktForSplitUpdate((Plan *)node, &splitupdatestate->ps.gpmon_pkt, estate);
return splitupdatestate;
}
/* Release Resources Requested by SplitUpdate node. */
void
ExecEndSplitUpdate(SplitUpdateState *node)
{
ExecFreeExprContext(&node->ps);
ExecClearTuple(node->ps.ps_ResultTupleSlot);
ExecClearTuple(node->insertTuple);
ExecClearTuple(node->deleteTuple);
ExecEndNode(outerPlanState(node));
EndPlanStateGpmonPkt(&node->ps);
}
/* Return number of TupleTableSlots used by SplitUpdate node.*/
int
ExecCountSlotsSplitUpdate(SplitUpdate *node)
{
return ExecCountSlotsNode(outerPlan(node)) + SPLITUPDATE_NSLOTS;
}
/* Tracing execution for GP Monitor. */
void
initGpmonPktForSplitUpdate(Plan *planNode, gpmon_packet_t *gpmon_pkt, EState *estate)
{
Assert(planNode != NULL && gpmon_pkt != NULL && IsA(planNode, SplitUpdate));
PerfmonNodeType type = PMNT_SplitUpdate;
InitPlanNodeGpmonPkt(planNode, gpmon_pkt, estate, type,
(int64)planNode->plan_rows,
NULL);
}