44
44
45
45
#undef TOAST_DEBUG
46
46
47
- /* Size of an EXTERNAL datum that contains a standard TOAST pointer */
48
- #define TOAST_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(struct varatt_external))
49
-
50
47
/*
51
48
* Testing whether an externally-stored value is compressed now requires
52
49
* comparing extsize (the actual length of the external data) to rawsize
@@ -87,25 +84,47 @@ static struct varlena *toast_fetch_datum_slice(struct varlena * attr,
87
84
* heap_tuple_fetch_attr -
88
85
*
89
86
* Public entry point to get back a toasted value from
90
- * external storage (possibly still in compressed format).
87
+ * external source (possibly still in compressed format).
91
88
*
92
89
* This will return a datum that contains all the data internally, ie, not
93
- * relying on external storage, but it can still be compressed or have a short
94
- * header.
90
+ * relying on external storage or memory , but it can still be compressed or
91
+ * have a short header.
95
92
----------
96
93
*/
97
94
struct varlena *
98
95
heap_tuple_fetch_attr (struct varlena * attr )
99
96
{
100
97
struct varlena * result ;
101
98
102
- if (VARATT_IS_EXTERNAL (attr ))
99
+ if (VARATT_IS_EXTERNAL_ONDISK (attr ))
103
100
{
104
101
/*
105
102
* This is an external stored plain value
106
103
*/
107
104
result = toast_fetch_datum (attr );
108
105
}
106
+ else if (VARATT_IS_EXTERNAL_INDIRECT (attr ))
107
+ {
108
+ /*
109
+ * copy into the caller's memory context. That's not required in all
110
+ * cases but sufficient for now since this is mainly used when we need
111
+ * to persist a Datum for unusually long time, like in a HOLD cursor.
112
+ */
113
+ struct varatt_indirect redirect ;
114
+ VARATT_EXTERNAL_GET_POINTER (redirect , attr );
115
+ attr = (struct varlena * )redirect .pointer ;
116
+
117
+ /* nested indirect Datums aren't allowed */
118
+ Assert (!VARATT_IS_EXTERNAL_INDIRECT (attr ));
119
+
120
+ /* doesn't make much sense, but better handle it */
121
+ if (VARATT_IS_EXTERNAL_ONDISK (attr ))
122
+ return heap_tuple_fetch_attr (attr );
123
+
124
+ /* copy datum verbatim */
125
+ result = (struct varlena * ) palloc (VARSIZE_ANY (attr ));
126
+ memcpy (result , attr , VARSIZE_ANY (attr ));
127
+ }
109
128
else
110
129
{
111
130
/*
@@ -128,7 +147,7 @@ heap_tuple_fetch_attr(struct varlena * attr)
128
147
struct varlena *
129
148
heap_tuple_untoast_attr (struct varlena * attr )
130
149
{
131
- if (VARATT_IS_EXTERNAL (attr ))
150
+ if (VARATT_IS_EXTERNAL_ONDISK (attr ))
132
151
{
133
152
/*
134
153
* This is an externally stored datum --- fetch it back from there
@@ -145,6 +164,17 @@ heap_tuple_untoast_attr(struct varlena * attr)
145
164
pfree (tmp );
146
165
}
147
166
}
167
+ else if (VARATT_IS_EXTERNAL_INDIRECT (attr ))
168
+ {
169
+ struct varatt_indirect redirect ;
170
+ VARATT_EXTERNAL_GET_POINTER (redirect , attr );
171
+ attr = (struct varlena * )redirect .pointer ;
172
+
173
+ /* nested indirect Datums aren't allowed */
174
+ Assert (!VARATT_IS_EXTERNAL_INDIRECT (attr ));
175
+
176
+ attr = heap_tuple_untoast_attr (attr );
177
+ }
148
178
else if (VARATT_IS_COMPRESSED (attr ))
149
179
{
150
180
/*
@@ -191,7 +221,7 @@ heap_tuple_untoast_attr_slice(struct varlena * attr,
191
221
char * attrdata ;
192
222
int32 attrsize ;
193
223
194
- if (VARATT_IS_EXTERNAL (attr ))
224
+ if (VARATT_IS_EXTERNAL_ONDISK (attr ))
195
225
{
196
226
struct varatt_external toast_pointer ;
197
227
@@ -204,6 +234,17 @@ heap_tuple_untoast_attr_slice(struct varlena * attr,
204
234
/* fetch it back (compressed marker will get set automatically) */
205
235
preslice = toast_fetch_datum (attr );
206
236
}
237
+ else if (VARATT_IS_EXTERNAL_INDIRECT (attr ))
238
+ {
239
+ struct varatt_indirect redirect ;
240
+ VARATT_EXTERNAL_GET_POINTER (redirect , attr );
241
+
242
+ /* nested indirect Datums aren't allowed */
243
+ Assert (!VARATT_IS_EXTERNAL_INDIRECT (redirect .pointer ));
244
+
245
+ return heap_tuple_untoast_attr_slice (redirect .pointer ,
246
+ sliceoffset , slicelength );
247
+ }
207
248
else
208
249
preslice = attr ;
209
250
@@ -267,14 +308,24 @@ toast_raw_datum_size(Datum value)
267
308
struct varlena * attr = (struct varlena * ) DatumGetPointer (value );
268
309
Size result ;
269
310
270
- if (VARATT_IS_EXTERNAL (attr ))
311
+ if (VARATT_IS_EXTERNAL_ONDISK (attr ))
271
312
{
272
313
/* va_rawsize is the size of the original datum -- including header */
273
314
struct varatt_external toast_pointer ;
274
315
275
316
VARATT_EXTERNAL_GET_POINTER (toast_pointer , attr );
276
317
result = toast_pointer .va_rawsize ;
277
318
}
319
+ else if (VARATT_IS_EXTERNAL_INDIRECT (attr ))
320
+ {
321
+ struct varatt_indirect toast_pointer ;
322
+ VARATT_EXTERNAL_GET_POINTER (toast_pointer , attr );
323
+
324
+ /* nested indirect Datums aren't allowed */
325
+ Assert (!VARATT_IS_EXTERNAL_INDIRECT (toast_pointer .pointer ));
326
+
327
+ return toast_raw_datum_size (PointerGetDatum (toast_pointer .pointer ));
328
+ }
278
329
else if (VARATT_IS_COMPRESSED (attr ))
279
330
{
280
331
/* here, va_rawsize is just the payload size */
@@ -308,7 +359,7 @@ toast_datum_size(Datum value)
308
359
struct varlena * attr = (struct varlena * ) DatumGetPointer (value );
309
360
Size result ;
310
361
311
- if (VARATT_IS_EXTERNAL (attr ))
362
+ if (VARATT_IS_EXTERNAL_ONDISK (attr ))
312
363
{
313
364
/*
314
365
* Attribute is stored externally - return the extsize whether
@@ -320,6 +371,16 @@ toast_datum_size(Datum value)
320
371
VARATT_EXTERNAL_GET_POINTER (toast_pointer , attr );
321
372
result = toast_pointer .va_extsize ;
322
373
}
374
+ else if (VARATT_IS_EXTERNAL_INDIRECT (attr ))
375
+ {
376
+ struct varatt_indirect toast_pointer ;
377
+ VARATT_EXTERNAL_GET_POINTER (toast_pointer , attr );
378
+
379
+ /* nested indirect Datums aren't allowed */
380
+ Assert (!VARATT_IS_EXTERNAL_INDIRECT (attr ));
381
+
382
+ return toast_datum_size (PointerGetDatum (toast_pointer .pointer ));
383
+ }
323
384
else if (VARATT_IS_SHORT (attr ))
324
385
{
325
386
result = VARSIZE_SHORT (attr );
@@ -387,8 +448,12 @@ toast_delete(Relation rel, HeapTuple oldtup)
387
448
{
388
449
Datum value = toast_values [i ];
389
450
390
- if (!toast_isnull [i ] && VARATT_IS_EXTERNAL (PointerGetDatum (value )))
451
+ if (toast_isnull [i ])
452
+ continue ;
453
+ else if (VARATT_IS_EXTERNAL_ONDISK (PointerGetDatum (value )))
391
454
toast_delete_datum (rel , value );
455
+ else if (VARATT_IS_EXTERNAL_INDIRECT (PointerGetDatum (value )))
456
+ elog (ERROR , "attempt to delete tuple containing indirect datums" );
392
457
}
393
458
}
394
459
}
@@ -490,13 +555,13 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
490
555
new_value = (struct varlena * ) DatumGetPointer (toast_values [i ]);
491
556
492
557
/*
493
- * If the old value is an external stored one , check if it has
494
- * changed so we have to delete it later.
558
+ * If the old value is stored on disk , check if it has changed so
559
+ * we have to delete it later.
495
560
*/
496
561
if (att [i ]-> attlen == -1 && !toast_oldisnull [i ] &&
497
- VARATT_IS_EXTERNAL (old_value ))
562
+ VARATT_IS_EXTERNAL_ONDISK (old_value ))
498
563
{
499
- if (toast_isnull [i ] || !VARATT_IS_EXTERNAL (new_value ) ||
564
+ if (toast_isnull [i ] || !VARATT_IS_EXTERNAL_ONDISK (new_value ) ||
500
565
memcmp ((char * ) old_value , (char * ) new_value ,
501
566
VARSIZE_EXTERNAL (old_value )) != 0 )
502
567
{
@@ -1258,6 +1323,8 @@ toast_save_datum(Relation rel, Datum value,
1258
1323
int32 data_todo ;
1259
1324
Pointer dval = DatumGetPointer (value );
1260
1325
1326
+ Assert (!VARATT_IS_EXTERNAL (value ));
1327
+
1261
1328
/*
1262
1329
* Open the toast relation and its index. We can use the index to check
1263
1330
* uniqueness of the OID we assign to the toasted item, even though it has
@@ -1341,7 +1408,7 @@ toast_save_datum(Relation rel, Datum value,
1341
1408
{
1342
1409
struct varatt_external old_toast_pointer ;
1343
1410
1344
- Assert (VARATT_IS_EXTERNAL (oldexternal ));
1411
+ Assert (VARATT_IS_EXTERNAL_ONDISK (oldexternal ));
1345
1412
/* Must copy to access aligned fields */
1346
1413
VARATT_EXTERNAL_GET_POINTER (old_toast_pointer , oldexternal );
1347
1414
if (old_toast_pointer .va_toastrelid == rel -> rd_toastoid )
@@ -1456,7 +1523,7 @@ toast_save_datum(Relation rel, Datum value,
1456
1523
* Create the TOAST pointer value that we'll return
1457
1524
*/
1458
1525
result = (struct varlena * ) palloc (TOAST_POINTER_SIZE );
1459
- SET_VARSIZE_EXTERNAL (result , TOAST_POINTER_SIZE );
1526
+ SET_VARTAG_EXTERNAL (result , VARTAG_ONDISK );
1460
1527
memcpy (VARDATA_EXTERNAL (result ), & toast_pointer , sizeof (toast_pointer ));
1461
1528
1462
1529
return PointerGetDatum (result );
@@ -1480,7 +1547,7 @@ toast_delete_datum(Relation rel, Datum value)
1480
1547
SysScanDesc toastscan ;
1481
1548
HeapTuple toasttup ;
1482
1549
1483
- if (!VARATT_IS_EXTERNAL (attr ))
1550
+ if (!VARATT_IS_EXTERNAL_ONDISK (attr ))
1484
1551
return ;
1485
1552
1486
1553
/* Must copy to access aligned fields */
@@ -1608,6 +1675,9 @@ toast_fetch_datum(struct varlena * attr)
1608
1675
char * chunkdata ;
1609
1676
int32 chunksize ;
1610
1677
1678
+ if (VARATT_IS_EXTERNAL_INDIRECT (attr ))
1679
+ elog (ERROR , "shouldn't be called for indirect tuples" );
1680
+
1611
1681
/* Must copy to access aligned fields */
1612
1682
VARATT_EXTERNAL_GET_POINTER (toast_pointer , attr );
1613
1683
@@ -1775,7 +1845,7 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
1775
1845
int32 chcpystrt ;
1776
1846
int32 chcpyend ;
1777
1847
1778
- Assert (VARATT_IS_EXTERNAL (attr ));
1848
+ Assert (VARATT_IS_EXTERNAL_ONDISK (attr ));
1779
1849
1780
1850
/* Must copy to access aligned fields */
1781
1851
VARATT_EXTERNAL_GET_POINTER (toast_pointer , attr );
0 commit comments