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