* ExecCrossPartitionUpdate --- Move an updated tuple to another partition. * * This works by first deleting the old tuple from the current partition, * followed by inserting the new tuple into the root parent table, that is, * mtstate->rootResultRelInfo. It will be re-routed from there to the * correct partition. * * Returns true if the tuple has been successfully moved, or if it's found
| 1672 | * and call this function again or perform a regular update accordingly. |
| 1673 | */ |
| 1674 | static bool |
| 1675 | ExecCrossPartitionUpdate(ModifyTableState *mtstate, |
| 1676 | ResultRelInfo *resultRelInfo, |
| 1677 | ItemPointer tupleid, HeapTuple oldtuple, |
| 1678 | TupleTableSlot *slot, TupleTableSlot *planSlot, |
| 1679 | EPQState *epqstate, int32 segid, bool canSetTag, |
| 1680 | TupleTableSlot **retry_slot, |
| 1681 | TupleTableSlot **inserted_tuple) |
| 1682 | { |
| 1683 | EState *estate = mtstate->ps.state; |
| 1684 | TupleConversionMap *tupconv_map; |
| 1685 | bool tuple_deleted; |
| 1686 | TupleTableSlot *epqslot = NULL; |
| 1687 | |
| 1688 | *inserted_tuple = NULL; |
| 1689 | *retry_slot = NULL; |
| 1690 | |
| 1691 | /* |
| 1692 | * Disallow an INSERT ON CONFLICT DO UPDATE that causes the original row |
| 1693 | * to migrate to a different partition. Maybe this can be implemented |
| 1694 | * some day, but it seems a fringe feature with little redeeming value. |
| 1695 | */ |
| 1696 | if (((ModifyTable *) mtstate->ps.plan)->onConflictAction == ONCONFLICT_UPDATE) |
| 1697 | ereport(ERROR, |
| 1698 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 1699 | errmsg("invalid ON UPDATE specification"), |
| 1700 | errdetail("The result tuple would appear in a different partition than the original tuple."))); |
| 1701 | |
| 1702 | /* |
| 1703 | * When an UPDATE is run directly on a leaf partition, simply fail with a |
| 1704 | * partition constraint violation error. |
| 1705 | */ |
| 1706 | if (resultRelInfo == mtstate->rootResultRelInfo) |
| 1707 | ExecPartitionCheckEmitError(resultRelInfo, slot, estate); |
| 1708 | |
| 1709 | /* Initialize tuple routing info if not already done. */ |
| 1710 | if (mtstate->mt_partition_tuple_routing == NULL) |
| 1711 | { |
| 1712 | Relation rootRel = mtstate->rootResultRelInfo->ri_RelationDesc; |
| 1713 | MemoryContext oldcxt; |
| 1714 | |
| 1715 | /* Things built here have to last for the query duration. */ |
| 1716 | oldcxt = MemoryContextSwitchTo(estate->es_query_cxt); |
| 1717 | |
| 1718 | mtstate->mt_partition_tuple_routing = |
| 1719 | ExecSetupPartitionTupleRouting(estate, rootRel); |
| 1720 | |
| 1721 | /* |
| 1722 | * Before a partition's tuple can be re-routed, it must first be |
| 1723 | * converted to the root's format, so we'll need a slot for storing |
| 1724 | * such tuples. |
| 1725 | */ |
| 1726 | Assert(mtstate->mt_root_tuple_slot == NULL); |
| 1727 | mtstate->mt_root_tuple_slot = table_slot_create(rootRel, NULL); |
| 1728 | |
| 1729 | MemoryContextSwitchTo(oldcxt); |
| 1730 | } |
| 1731 |
no test coverage detected