Thanks to visit codestin.com
Credit goes to github.com

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

Lines changed: 6 additions & 168 deletions
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

Lines changed: 71 additions & 90 deletions
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)