Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4da597e

Browse files
committed
Make TupleTableSlots extensible, finish split of existing slot type.
This commit completes the work prepared in 1a0586d, splitting the old TupleTableSlot implementation (which could store buffer, heap, minimal and virtual slots) into four different slot types. As described in the aforementioned commit, this is done with the goal of making tuple table slots extensible, to allow for pluggable table access methods. To achieve runtime extensibility for TupleTableSlots, operations on slots that can differ between types of slots are performed using the TupleTableSlotOps struct provided at slot creation time. That includes information from the size of TupleTableSlot struct to be allocated, initialization, deforming etc. See the struct's definition for more detailed information about callbacks TupleTableSlotOps. I decided to rename TTSOpsBufferTuple to TTSOpsBufferHeapTuple and ExecCopySlotTuple to ExecCopySlotHeapTuple, as that seems more consistent with other naming introduced in recent patches. There's plenty optimization potential in the slot implementation, but according to benchmarking the state after this commit has similar performance characteristics to before this set of changes, which seems sufficient. There's a few changes in execReplication.c that currently need to poke through the slot abstraction, that'll be repaired once the pluggable storage patchset provides the necessary infrastructure. Author: Andres Freund and Ashutosh Bapat, with changes by Amit Khandekar Discussion: https://postgr.es/m/20181105210039.hh4vvi4vwoq5ba2q@alap3.anarazel.de
1 parent 0201d79 commit 4da597e

27 files changed

+1505
-867
lines changed

src/backend/access/common/heaptuple.c

+3-181
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
#define VARLENA_ATT_IS_PACKABLE(att) \
7272
((att)->attstorage != 'p')
7373

74+
static Datum getmissingattr(TupleDesc tupleDesc, int attnum, bool *isnull);
75+
7476

7577
/* ----------------------------------------------------------------
7678
* misc support routines
@@ -80,7 +82,7 @@
8082
/*
8183
* Return the missing value of an attribute, or NULL if there isn't one.
8284
*/
83-
Datum
85+
static Datum
8486
getmissingattr(TupleDesc tupleDesc,
8587
int attnum, bool *isnull)
8688
{
@@ -1350,186 +1352,6 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
13501352
values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]);
13511353
}
13521354

1353-
/*
1354-
* slot_deform_tuple
1355-
* Given a TupleTableSlot, extract data from the slot's physical tuple
1356-
* into its Datum/isnull arrays. Data is extracted up through the
1357-
* natts'th column (caller must ensure this is a legal column number).
1358-
*
1359-
* This is essentially an incremental version of heap_deform_tuple:
1360-
* on each call we extract attributes up to the one needed, without
1361-
* re-computing information about previously extracted attributes.
1362-
* slot->tts_nvalid is the number of attributes already extracted.
1363-
*/
1364-
void
1365-
slot_deform_tuple(TupleTableSlot *slot, int natts)
1366-
{
1367-
HeapTuple tuple = slot->tts_tuple;
1368-
TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1369-
Datum *values = slot->tts_values;
1370-
bool *isnull = slot->tts_isnull;
1371-
HeapTupleHeader tup = tuple->t_data;
1372-
bool hasnulls = HeapTupleHasNulls(tuple);
1373-
int attnum;
1374-
char *tp; /* ptr to tuple data */
1375-
uint32 off; /* offset in tuple data */
1376-
bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
1377-
bool slow; /* can we use/set attcacheoff? */
1378-
1379-
/*
1380-
* Check whether the first call for this tuple, and initialize or restore
1381-
* loop state.
1382-
*/
1383-
attnum = slot->tts_nvalid;
1384-
if (attnum == 0)
1385-
{
1386-
/* Start from the first attribute */
1387-
off = 0;
1388-
slow = false;
1389-
}
1390-
else
1391-
{
1392-
/* Restore state from previous execution */
1393-
off = slot->tts_off;
1394-
slow = TTS_SLOW(slot);
1395-
}
1396-
1397-
tp = (char *) tup + tup->t_hoff;
1398-
1399-
for (; attnum < natts; attnum++)
1400-
{
1401-
Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
1402-
1403-
if (hasnulls && att_isnull(attnum, bp))
1404-
{
1405-
values[attnum] = (Datum) 0;
1406-
isnull[attnum] = true;
1407-
slow = true; /* can't use attcacheoff anymore */
1408-
continue;
1409-
}
1410-
1411-
isnull[attnum] = false;
1412-
1413-
if (!slow && thisatt->attcacheoff >= 0)
1414-
off = thisatt->attcacheoff;
1415-
else if (thisatt->attlen == -1)
1416-
{
1417-
/*
1418-
* We can only cache the offset for a varlena attribute if the
1419-
* offset is already suitably aligned, so that there would be no
1420-
* pad bytes in any case: then the offset will be valid for either
1421-
* an aligned or unaligned value.
1422-
*/
1423-
if (!slow &&
1424-
off == att_align_nominal(off, thisatt->attalign))
1425-
thisatt->attcacheoff = off;
1426-
else
1427-
{
1428-
off = att_align_pointer(off, thisatt->attalign, -1,
1429-
tp + off);
1430-
slow = true;
1431-
}
1432-
}
1433-
else
1434-
{
1435-
/* not varlena, so safe to use att_align_nominal */
1436-
off = att_align_nominal(off, thisatt->attalign);
1437-
1438-
if (!slow)
1439-
thisatt->attcacheoff = off;
1440-
}
1441-
1442-
values[attnum] = fetchatt(thisatt, tp + off);
1443-
1444-
off = att_addlength_pointer(off, thisatt->attlen, tp + off);
1445-
1446-
if (thisatt->attlen <= 0)
1447-
slow = true; /* can't use attcacheoff anymore */
1448-
}
1449-
1450-
/*
1451-
* Save state for next execution
1452-
*/
1453-
slot->tts_nvalid = attnum;
1454-
slot->tts_off = off;
1455-
if (slow)
1456-
slot->tts_flags |= TTS_FLAG_SLOW;
1457-
else
1458-
slot->tts_flags &= ~TTS_FLAG_SLOW;
1459-
}
1460-
1461-
/*
1462-
* slot_attisnull
1463-
* Detect whether an attribute of the slot is null, without
1464-
* actually fetching it.
1465-
*/
1466-
bool
1467-
slot_attisnull(TupleTableSlot *slot, int attnum)
1468-
{
1469-
HeapTuple tuple = slot->tts_tuple;
1470-
TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1471-
1472-
/*
1473-
* system attributes are handled by heap_attisnull
1474-
*/
1475-
if (attnum <= 0)
1476-
{
1477-
if (tuple == NULL) /* internal error */
1478-
elog(ERROR, "cannot extract system attribute from virtual tuple");
1479-
if (tuple == &(slot->tts_minhdr)) /* internal error */
1480-
elog(ERROR, "cannot extract system attribute from minimal tuple");
1481-
return heap_attisnull(tuple, attnum, tupleDesc);
1482-
}
1483-
1484-
/*
1485-
* fast path if desired attribute already cached
1486-
*/
1487-
if (attnum <= slot->tts_nvalid)
1488-
return slot->tts_isnull[attnum - 1];
1489-
1490-
/*
1491-
* return NULL if attnum is out of range according to the tupdesc
1492-
*/
1493-
if (attnum > tupleDesc->natts)
1494-
return true;
1495-
1496-
/*
1497-
* otherwise we had better have a physical tuple (tts_nvalid should equal
1498-
* natts in all virtual-tuple cases)
1499-
*/
1500-
if (tuple == NULL) /* internal error */
1501-
elog(ERROR, "cannot extract attribute from empty tuple slot");
1502-
1503-
/* and let the tuple tell it */
1504-
return heap_attisnull(tuple, attnum, tupleDesc);
1505-
}
1506-
1507-
/*
1508-
* slot_getsysattr
1509-
* This function fetches a system attribute of the slot's current tuple.
1510-
* Unlike slot_getattr, if the slot does not contain system attributes,
1511-
* this will return false (with a NULL attribute value) instead of
1512-
* throwing an error.
1513-
*/
1514-
bool
1515-
slot_getsysattr(TupleTableSlot *slot, int attnum,
1516-
Datum *value, bool *isnull)
1517-
{
1518-
HeapTuple tuple = slot->tts_tuple;
1519-
1520-
Assert(attnum < 0); /* else caller error */
1521-
if (tuple == NULL ||
1522-
tuple == &(slot->tts_minhdr))
1523-
{
1524-
/* No physical tuple, or minimal tuple, so fail */
1525-
*value = (Datum) 0;
1526-
*isnull = true;
1527-
return false;
1528-
}
1529-
*value = heap_getsysattr(tuple, attnum, slot->tts_tupleDescriptor, isnull);
1530-
return true;
1531-
}
1532-
15331355
/*
15341356
* heap_freetuple
15351357
*/

src/backend/catalog/index.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,9 @@ FormIndexDatum(IndexInfo *indexInfo,
20412041
Datum iDatum;
20422042
bool isNull;
20432043

2044-
if (keycol != 0)
2044+
if (keycol < 0)
2045+
iDatum = slot_getsysattr(slot, keycol, &isNull);
2046+
else if (keycol != 0)
20452047
{
20462048
/*
20472049
* Plain index column; get the value we need directly from the

src/backend/commands/copy.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2850,7 +2850,7 @@ CopyFrom(CopyState cstate)
28502850
* freed after each batch insert.
28512851
*/
28522852
oldcontext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
2853-
tuple = ExecCopySlotTuple(slot);
2853+
tuple = ExecCopySlotHeapTuple(slot);
28542854
MemoryContextSwitchTo(oldcontext);
28552855
}
28562856

src/backend/commands/createas.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self)
589589
* get the heap tuple out of the tuple table slot, making sure we have a
590590
* writable copy
591591
*/
592-
tuple = ExecCopySlotTuple(slot);
592+
tuple = ExecCopySlotHeapTuple(slot);
593593

594594
/*
595595
* force assignment of new OID (see comments in ExecInsert)

src/backend/commands/matview.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ transientrel_receive(TupleTableSlot *slot, DestReceiver *self)
484484
* get the heap tuple out of the tuple table slot, making sure we have a
485485
* writable copy
486486
*/
487-
tuple = ExecCopySlotTuple(slot);
487+
tuple = ExecCopySlotHeapTuple(slot);
488488

489489
heap_insert(myState->transientrel,
490490
tuple,

src/backend/executor/execCurrent.c

+8-10
Original file line numberDiff line numberDiff line change
@@ -218,27 +218,25 @@ execCurrentOf(CurrentOfExpr *cexpr,
218218
ItemPointer tuple_tid;
219219

220220
#ifdef USE_ASSERT_CHECKING
221-
if (!slot_getsysattr(scanstate->ss_ScanTupleSlot,
222-
TableOidAttributeNumber,
223-
&ldatum,
224-
&lisnull))
221+
ldatum = slot_getsysattr(scanstate->ss_ScanTupleSlot,
222+
TableOidAttributeNumber,
223+
&lisnull);
224+
if (lisnull)
225225
ereport(ERROR,
226226
(errcode(ERRCODE_INVALID_CURSOR_STATE),
227227
errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"",
228228
cursor_name, table_name)));
229-
Assert(!lisnull);
230229
Assert(DatumGetObjectId(ldatum) == table_oid);
231230
#endif
232231

233-
if (!slot_getsysattr(scanstate->ss_ScanTupleSlot,
234-
SelfItemPointerAttributeNumber,
235-
&ldatum,
236-
&lisnull))
232+
ldatum = slot_getsysattr(scanstate->ss_ScanTupleSlot,
233+
SelfItemPointerAttributeNumber,
234+
&lisnull);
235+
if (lisnull)
237236
ereport(ERROR,
238237
(errcode(ERRCODE_INVALID_CURSOR_STATE),
239238
errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"",
240239
cursor_name, table_name)));
241-
Assert(!lisnull);
242240
tuple_tid = (ItemPointer) DatumGetPointer(ldatum);
243241

244242
*current_tid = *tuple_tid;

src/backend/executor/execExprInterp.c

+8-8
Original file line numberDiff line numberDiff line change
@@ -1875,11 +1875,11 @@ CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot)
18751875
* Should probably fixed at some point, but for now it's easier to allow
18761876
* buffer and heap tuples to be used interchangably.
18771877
*/
1878-
if (slot->tts_ops == &TTSOpsBufferTuple &&
1878+
if (slot->tts_ops == &TTSOpsBufferHeapTuple &&
18791879
op->d.fetch.kind == &TTSOpsHeapTuple)
18801880
return;
18811881
if (slot->tts_ops == &TTSOpsHeapTuple &&
1882-
op->d.fetch.kind == &TTSOpsBufferTuple)
1882+
op->d.fetch.kind == &TTSOpsBufferHeapTuple)
18831883
return;
18841884

18851885
/*
@@ -4025,15 +4025,15 @@ void
40254025
ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
40264026
TupleTableSlot *slot)
40274027
{
4028-
bool success;
4028+
Datum d;
40294029

40304030
/* slot_getsysattr has sufficient defenses against bad attnums */
4031-
success = slot_getsysattr(slot,
4032-
op->d.var.attnum,
4033-
op->resvalue,
4034-
op->resnull);
4031+
d = slot_getsysattr(slot,
4032+
op->d.var.attnum,
4033+
op->resnull);
4034+
*op->resvalue = d;
40354035
/* this ought to be unreachable, but it's cheap enough to check */
4036-
if (unlikely(!success))
4036+
if (unlikely(*op->resnull))
40374037
elog(ERROR, "failed to fetch attribute from slot");
40384038
}
40394039

0 commit comments

Comments
 (0)