@@ -332,6 +332,113 @@ detoast_attr_slice(struct varlena *attr,
332
332
return result ;
333
333
}
334
334
335
+ /* ----------
336
+ * create_detoast_iterator -
337
+ *
338
+ * It only makes sense to initialize a de-TOAST iterator for external on-disk values.
339
+ *
340
+ * ----------
341
+ */
342
+ DetoastIterator
343
+ create_detoast_iterator (struct varlena * attr )
344
+ {
345
+ struct varatt_external toast_pointer ;
346
+ DetoastIterator iter ;
347
+ if (VARATT_IS_EXTERNAL_ONDISK (attr ))
348
+ {
349
+ FetchDatumIterator fetch_iter ;
350
+
351
+ iter = (DetoastIterator )palloc0 (sizeof (DetoastIteratorData ));
352
+ iter -> done = false;
353
+ iter -> nrefs = 1 ;
354
+
355
+ /* This is an externally stored datum --- initialize fetch datum iterator */
356
+ iter -> fetch_datum_iterator = fetch_iter = create_fetch_datum_iterator (attr );
357
+ VARATT_EXTERNAL_GET_POINTER (toast_pointer ,attr );
358
+ if (VARATT_EXTERNAL_IS_COMPRESSED (toast_pointer ))
359
+ {
360
+ iter -> compressed = true;
361
+
362
+ /* prepare buffer to received decompressed data */
363
+ iter -> buf = create_toast_buffer (toast_pointer .va_rawsize , false);
364
+
365
+ /* initialize state for pglz_decompress_iterate() */
366
+ iter -> ctrl = 0 ;
367
+ iter -> ctrlc = INVALID_CTRLC ;
368
+ }
369
+ else
370
+ {
371
+ iter -> compressed = false;
372
+
373
+ /* point the buffer directly at the raw data */
374
+ iter -> buf = fetch_iter -> buf ;
375
+ }
376
+ return iter ;
377
+ }
378
+ else if (VARATT_IS_EXTERNAL_INDIRECT (attr ))
379
+ {
380
+ /* indirect pointer --- dereference it */
381
+ struct varatt_indirect redirect ;
382
+
383
+ VARATT_EXTERNAL_GET_POINTER (redirect ,attr );
384
+ attr = (struct varlena * )redirect .pointer ;
385
+
386
+ /* nested indirect Datums aren't allowed */
387
+ Assert (!VARATT_IS_EXTERNAL_INDIRECT (attr ));
388
+
389
+ /* recurse in case value is still extended in some other way */
390
+ return create_detoast_iterator (attr );
391
+
392
+ }
393
+ else if (VARATT_IS_COMPRESSED (attr ))
394
+ {
395
+ ToastBuffer * buf ;
396
+
397
+ iter = (DetoastIterator )palloc0 (sizeof (DetoastIteratorData ));
398
+ iter -> done = false;
399
+ iter -> nrefs = 1 ;
400
+
401
+ iter -> fetch_datum_iterator = palloc0 (sizeof (* iter -> fetch_datum_iterator ));
402
+ iter -> fetch_datum_iterator -> buf = buf = create_toast_buffer (VARSIZE_ANY (attr ), true);
403
+ iter -> fetch_datum_iterator -> done = true;
404
+ iter -> compressed = true;
405
+
406
+ memcpy ((void * )buf -> buf ,attr ,VARSIZE_ANY (attr ));
407
+ buf -> limit = (char * )buf -> capacity ;
408
+
409
+ /* prepare buffer to received decompressed data */
410
+ iter -> buf = create_toast_buffer (TOAST_COMPRESS_RAWSIZE (attr )+ VARHDRSZ , false);
411
+
412
+ /* initialize state for pglz_decompress_iterate() */
413
+ iter -> ctrl = 0 ;
414
+ iter -> ctrlc = INVALID_CTRLC ;
415
+ return iter ;
416
+ }
417
+ else
418
+ /* in-line value -- no iteration used, even if it's compressed */
419
+ return NULL ;
420
+ }
421
+
422
+ /* ----------
423
+ * free_detoast_iterator -
424
+ *
425
+ * Free memory used by the de-TOAST iterator, including buffers and
426
+ * fetch datum iterator.
427
+ * ----------
428
+ */
429
+ void
430
+ free_detoast_iterator (DetoastIterator iter )
431
+ {
432
+ if (iter == NULL )
433
+ return ;
434
+ if (-- iter -> nrefs > 0 )
435
+ return ;
436
+ if (iter -> compressed )
437
+ free_toast_buffer (iter -> buf );
438
+ free_fetch_datum_iterator (iter -> fetch_datum_iterator );
439
+ pfree (iter );
440
+ }
441
+
335
442
/* ----------
336
443
* toast_fetch_datum -
337
444
*