@@ -332,6 +332,113 @@ detoast_attr_slice(struct varlena *attr,
332332 return result ;
333333}
334334
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+
335442/* ----------
336443 * toast_fetch_datum -
337444 *
0 commit comments