Skip to content

Commit a90641e

Browse files
committed
Revert "Rewrite some RI code to avoid using SPI"
This reverts commit 99392cd. We'd rather rewrite ri_triggers.c as a whole rather than piecemeal. Discussion: https://postgr.es/m/[email protected]
1 parent 3e707fb commit a90641e

File tree

7 files changed

+317
-605
lines changed

7 files changed

+317
-605
lines changed

src/backend/executor/execPartition.c

+6-168
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,8 @@ static void FormPartitionKeyDatum(PartitionDispatch pd,
176176
EState *estate,
177177
Datum *values,
178178
bool *isnull);
179-
static int get_partition_for_tuple(PartitionKey key,
180-
PartitionDesc partdesc,
181-
Datum *values, bool *isnull);
179+
static int get_partition_for_tuple(PartitionDispatch pd, Datum *values,
180+
bool *isnull);
182181
static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
183182
Datum *values,
184183
bool *isnull,
@@ -319,9 +318,7 @@ ExecFindPartition(ModifyTableState *mtstate,
319318
* these values, error out.
320319
*/
321320
if (partdesc->nparts == 0 ||
322-
(partidx = get_partition_for_tuple(dispatch->key,
323-
dispatch->partdesc,
324-
values, isnull)) < 0)
321+
(partidx = get_partition_for_tuple(dispatch, values, isnull)) < 0)
325322
{
326323
char *val_desc;
327324

@@ -1344,12 +1341,12 @@ FormPartitionKeyDatum(PartitionDispatch pd,
13441341
* found or -1 if none found.
13451342
*/
13461343
static int
1347-
get_partition_for_tuple(PartitionKey key,
1348-
PartitionDesc partdesc,
1349-
Datum *values, bool *isnull)
1344+
get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull)
13501345
{
13511346
int bound_offset;
13521347
int part_index = -1;
1348+
PartitionKey key = pd->key;
1349+
PartitionDesc partdesc = pd->partdesc;
13531350
PartitionBoundInfo boundinfo = partdesc->boundinfo;
13541351

13551352
/* Route as appropriate based on partitioning strategy. */
@@ -1441,165 +1438,6 @@ get_partition_for_tuple(PartitionKey key,
14411438
return part_index;
14421439
}
14431440

1444-
/*
1445-
* ExecGetLeafPartitionForKey
1446-
* Finds the leaf partition of partitioned table 'root_rel' that would
1447-
* contain the specified key tuple.
1448-
*
1449-
* A subset of the table's columns (including all of the partition key columns)
1450-
* must be specified:
1451-
* - 'key_natts' indicats the number of columns contained in the key
1452-
* - 'key_attnums' indicates their attribute numbers as defined in 'root_rel'
1453-
* - 'key_vals' and 'key_nulls' specify the key tuple
1454-
*
1455-
* Returns the leaf partition, locked with the given lockmode, or NULL if
1456-
* there isn't one. Caller is responsibly for closing it. All intermediate
1457-
* partitions are also locked with the same lockmode. Caller must have locked
1458-
* the root already.
1459-
*
1460-
* In addition, the OID of the index of a unique constraint on the root table
1461-
* must be given as 'root_idxoid'; *leaf_idxoid will be set to the OID of the
1462-
* corresponding index on the returned leaf partition. (This can be used by
1463-
* caller to search for a tuple matching the key in the leaf partition.)
1464-
*
1465-
* This works because the unique key defined on the root relation is required
1466-
* to contain the partition key columns of all of the ancestors that lead up to
1467-
* a given leaf partition.
1468-
*/
1469-
Relation
1470-
ExecGetLeafPartitionForKey(Relation root_rel, int key_natts,
1471-
const AttrNumber *key_attnums,
1472-
Datum *key_vals, char *key_nulls,
1473-
Oid root_idxoid, int lockmode,
1474-
Oid *leaf_idxoid)
1475-
{
1476-
Relation found_leafpart = NULL;
1477-
Relation rel = root_rel;
1478-
Oid constr_idxoid = root_idxoid;
1479-
PartitionDirectory partdir;
1480-
1481-
Assert(root_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
1482-
1483-
*leaf_idxoid = InvalidOid;
1484-
1485-
partdir = CreatePartitionDirectory(CurrentMemoryContext, true);
1486-
1487-
/*
1488-
* Descend through partitioned parents to find the leaf partition that
1489-
* would accept a row with the provided key values, starting with the root
1490-
* parent.
1491-
*/
1492-
for (;;)
1493-
{
1494-
PartitionKey partkey = RelationGetPartitionKey(rel);
1495-
PartitionDesc partdesc;
1496-
Datum partkey_vals[PARTITION_MAX_KEYS];
1497-
bool partkey_isnull[PARTITION_MAX_KEYS];
1498-
AttrNumber *root_partattrs = partkey->partattrs;
1499-
int found_att;
1500-
int partidx;
1501-
Oid partoid;
1502-
1503-
CHECK_FOR_INTERRUPTS();
1504-
1505-
/*
1506-
* Collect partition key values from the unique key.
1507-
*
1508-
* Because we only have the root table's copy of pk_attnums, must map
1509-
* any non-root table's partition key attribute numbers to the root
1510-
* table's.
1511-
*/
1512-
if (rel != root_rel)
1513-
{
1514-
/*
1515-
* map->attnums will contain root table attribute numbers for each
1516-
* attribute of the current partitioned relation.
1517-
*/
1518-
AttrMap *map;
1519-
1520-
map = build_attrmap_by_name_if_req(RelationGetDescr(root_rel),
1521-
RelationGetDescr(rel));
1522-
if (map)
1523-
{
1524-
root_partattrs = palloc(partkey->partnatts *
1525-
sizeof(AttrNumber));
1526-
for (int att = 0; att < partkey->partnatts; att++)
1527-
{
1528-
AttrNumber partattno = partkey->partattrs[att];
1529-
1530-
root_partattrs[att] = map->attnums[partattno - 1];
1531-
}
1532-
1533-
free_attrmap(map);
1534-
}
1535-
}
1536-
1537-
/*
1538-
* Map the values/isnulls to match the partition description, as
1539-
* necessary.
1540-
*
1541-
* (Referenced key specification does not allow expressions, so there
1542-
* would not be expressions in the partition keys either.)
1543-
*/
1544-
Assert(partkey->partexprs == NIL);
1545-
found_att = 0;
1546-
for (int keyatt = 0; keyatt < key_natts; keyatt++)
1547-
{
1548-
for (int att = 0; att < partkey->partnatts; att++)
1549-
{
1550-
if (root_partattrs[att] == key_attnums[keyatt])
1551-
{
1552-
partkey_vals[found_att] = key_vals[keyatt];
1553-
partkey_isnull[found_att] = (key_nulls[keyatt] == 'n');
1554-
found_att++;
1555-
break;
1556-
}
1557-
}
1558-
}
1559-
/* We had better have found values for all partition keys */
1560-
Assert(found_att == partkey->partnatts);
1561-
1562-
if (root_partattrs != partkey->partattrs)
1563-
pfree(root_partattrs);
1564-
1565-
/* Get the PartitionDesc using the partition directory machinery. */
1566-
partdesc = PartitionDirectoryLookup(partdir, rel);
1567-
if (partdesc->nparts == 0)
1568-
break;
1569-
1570-
/* Find the partition for the key. */
1571-
partidx = get_partition_for_tuple(partkey, partdesc,
1572-
partkey_vals, partkey_isnull);
1573-
Assert(partidx < 0 || partidx < partdesc->nparts);
1574-
1575-
/* close the previous parent if any, but keep lock */
1576-
if (rel != root_rel)
1577-
table_close(rel, NoLock);
1578-
1579-
/* No partition found. */
1580-
if (partidx < 0)
1581-
break;
1582-
1583-
partoid = partdesc->oids[partidx];
1584-
rel = table_open(partoid, lockmode);
1585-
constr_idxoid = index_get_partition(rel, constr_idxoid);
1586-
1587-
/*
1588-
* We're done if the partition is a leaf, else find its partition in
1589-
* the next iteration.
1590-
*/
1591-
if (partdesc->is_leaf[partidx])
1592-
{
1593-
*leaf_idxoid = constr_idxoid;
1594-
found_leafpart = rel;
1595-
break;
1596-
}
1597-
}
1598-
1599-
DestroyPartitionDirectory(partdir);
1600-
return found_leafpart;
1601-
}
1602-
16031441
/*
16041442
* ExecBuildSlotPartitionKeyDescription
16051443
*

src/backend/executor/nodeLockRows.c

+71-90
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ ExecLockRows(PlanState *pstate)
7979
Datum datum;
8080
bool isNull;
8181
ItemPointerData tid;
82+
TM_FailureData tmfd;
8283
LockTupleMode lockmode;
84+
int lockflags = 0;
85+
TM_Result test;
8386
TupleTableSlot *markSlot;
8487

8588
/* clear any leftover test tuple for this rel */
@@ -176,11 +179,74 @@ ExecLockRows(PlanState *pstate)
176179
break;
177180
}
178181

179-
/* skip tuple if it couldn't be locked */
180-
if (!ExecLockTableTuple(erm->relation, &tid, markSlot,
181-
estate->es_snapshot, estate->es_output_cid,
182-
lockmode, erm->waitPolicy, &epq_needed))
183-
goto lnext;
182+
lockflags = TUPLE_LOCK_FLAG_LOCK_UPDATE_IN_PROGRESS;
183+
if (!IsolationUsesXactSnapshot())
184+
lockflags |= TUPLE_LOCK_FLAG_FIND_LAST_VERSION;
185+
186+
test = table_tuple_lock(erm->relation, &tid, estate->es_snapshot,
187+
markSlot, estate->es_output_cid,
188+
lockmode, erm->waitPolicy,
189+
lockflags,
190+
&tmfd);
191+
192+
switch (test)
193+
{
194+
case TM_WouldBlock:
195+
/* couldn't lock tuple in SKIP LOCKED mode */
196+
goto lnext;
197+
198+
case TM_SelfModified:
199+
200+
/*
201+
* The target tuple was already updated or deleted by the
202+
* current command, or by a later command in the current
203+
* transaction. We *must* ignore the tuple in the former
204+
* case, so as to avoid the "Halloween problem" of repeated
205+
* update attempts. In the latter case it might be sensible
206+
* to fetch the updated tuple instead, but doing so would
207+
* require changing heap_update and heap_delete to not
208+
* complain about updating "invisible" tuples, which seems
209+
* pretty scary (table_tuple_lock will not complain, but few
210+
* callers expect TM_Invisible, and we're not one of them). So
211+
* for now, treat the tuple as deleted and do not process.
212+
*/
213+
goto lnext;
214+
215+
case TM_Ok:
216+
217+
/*
218+
* Got the lock successfully, the locked tuple saved in
219+
* markSlot for, if needed, EvalPlanQual testing below.
220+
*/
221+
if (tmfd.traversed)
222+
epq_needed = true;
223+
break;
224+
225+
case TM_Updated:
226+
if (IsolationUsesXactSnapshot())
227+
ereport(ERROR,
228+
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
229+
errmsg("could not serialize access due to concurrent update")));
230+
elog(ERROR, "unexpected table_tuple_lock status: %u",
231+
test);
232+
break;
233+
234+
case TM_Deleted:
235+
if (IsolationUsesXactSnapshot())
236+
ereport(ERROR,
237+
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
238+
errmsg("could not serialize access due to concurrent update")));
239+
/* tuple was deleted so don't return it */
240+
goto lnext;
241+
242+
case TM_Invisible:
243+
elog(ERROR, "attempted to lock invisible tuple");
244+
break;
245+
246+
default:
247+
elog(ERROR, "unrecognized table_tuple_lock status: %u",
248+
test);
249+
}
184250

185251
/* Remember locked tuple's TID for EPQ testing and WHERE CURRENT OF */
186252
erm->curCtid = tid;
@@ -215,91 +281,6 @@ ExecLockRows(PlanState *pstate)
215281
return slot;
216282
}
217283

218-
/*
219-
* ExecLockTableTuple
220-
* Locks tuple with the specified TID in lockmode following given wait
221-
* policy
222-
*
223-
* Returns true if the tuple was successfully locked. Locked tuple is loaded
224-
* into provided slot.
225-
*/
226-
bool
227-
ExecLockTableTuple(Relation relation, ItemPointer tid, TupleTableSlot *slot,
228-
Snapshot snapshot, CommandId cid,
229-
LockTupleMode lockmode, LockWaitPolicy waitPolicy,
230-
bool *epq_needed)
231-
{
232-
TM_FailureData tmfd;
233-
int lockflags = TUPLE_LOCK_FLAG_LOCK_UPDATE_IN_PROGRESS;
234-
TM_Result test;
235-
236-
if (!IsolationUsesXactSnapshot())
237-
lockflags |= TUPLE_LOCK_FLAG_FIND_LAST_VERSION;
238-
239-
test = table_tuple_lock(relation, tid, snapshot, slot, cid, lockmode,
240-
waitPolicy, lockflags, &tmfd);
241-
242-
switch (test)
243-
{
244-
case TM_WouldBlock:
245-
/* couldn't lock tuple in SKIP LOCKED mode */
246-
return false;
247-
248-
case TM_SelfModified:
249-
250-
/*
251-
* The target tuple was already updated or deleted by the current
252-
* command, or by a later command in the current transaction. We
253-
* *must* ignore the tuple in the former case, so as to avoid the
254-
* "Halloween problem" of repeated update attempts. In the latter
255-
* case it might be sensible to fetch the updated tuple instead,
256-
* but doing so would require changing heap_update and heap_delete
257-
* to not complain about updating "invisible" tuples, which seems
258-
* pretty scary (table_tuple_lock will not complain, but few
259-
* callers expect TM_Invisible, and we're not one of them). So for
260-
* now, treat the tuple as deleted and do not process.
261-
*/
262-
return false;
263-
264-
case TM_Ok:
265-
266-
/*
267-
* Got the lock successfully, the locked tuple saved in slot for
268-
* EvalPlanQual, if asked by the caller.
269-
*/
270-
if (tmfd.traversed && epq_needed)
271-
*epq_needed = true;
272-
break;
273-
274-
case TM_Updated:
275-
if (IsolationUsesXactSnapshot())
276-
ereport(ERROR,
277-
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
278-
errmsg("could not serialize access due to concurrent update")));
279-
elog(ERROR, "unexpected table_tuple_lock status: %u",
280-
test);
281-
break;
282-
283-
case TM_Deleted:
284-
if (IsolationUsesXactSnapshot())
285-
ereport(ERROR,
286-
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
287-
errmsg("could not serialize access due to concurrent update")));
288-
/* tuple was deleted so don't return it */
289-
return false;
290-
291-
case TM_Invisible:
292-
elog(ERROR, "attempted to lock invisible tuple");
293-
return false;
294-
295-
default:
296-
elog(ERROR, "unrecognized table_tuple_lock status: %u", test);
297-
return false;
298-
}
299-
300-
return true;
301-
}
302-
303284
/* ----------------------------------------------------------------
304285
* ExecInitLockRows
305286
*

0 commit comments

Comments
 (0)