diff --git a/page/page0zip.c b/page/page0zip.c
index f793d62c17f..e5c79c33564 100644
--- a/page/page0zip.c
+++ b/page/page0zip.c
@@ -1629,6 +1629,579 @@ page_zip_apply_log(
 	}
 }
 
+/**************************************************************************
+Decompress the records of a node pointer page. */
+static
+ibool
+page_zip_decompress_node_ptrs(
+/*==========================*/
+					/* out: TRUE on success,
+					FALSE on failure */
+	page_zip_des_t*	page_zip,	/* in/out: compressed page */
+	z_stream*	d_stream,	/* in/out: compressed page stream */
+	rec_t**		recs,		/* in: dense page directory
+					sorted by address */
+	ulint		n_dense,	/* in: size of recs[] */
+	dict_index_t*	index,		/* in: the index of the page */
+	ulint*		offsets,	/* in/out: temporary offsets */
+	mem_heap_t*	heap)		/* in: temporary memory heap */
+{
+	ulint		heap_status = REC_STATUS_NODE_PTR
+		| 2 << REC_HEAP_NO_SHIFT;
+	ulint		slot;
+	const byte*	storage;
+
+	/* Subtract the space reserved for uncompressed data. */
+	d_stream->avail_in -= n_dense
+		* (PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE);
+
+	/* Decompress the records in heap_no order. */
+	for (slot = 0; slot < n_dense; slot++) {
+		rec_t*	rec = recs[slot];
+
+		d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
+			- d_stream->next_out;
+
+		ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
+		      - PAGE_ZIP_START - PAGE_DIR);
+		switch (inflate(d_stream, Z_SYNC_FLUSH)) {
+		case Z_STREAM_END:
+			/* Apparently, n_dense has grown
+			since the time the page was last compressed. */
+			goto zlib_done;
+		case Z_OK:
+		case Z_BUF_ERROR:
+			if (!d_stream->avail_out) {
+				break;
+			}
+			/* fall through */
+		default:
+			goto zlib_error;
+		}
+
+		ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
+		/* Prepare to decompress the data bytes. */
+		d_stream->next_out = rec;
+		/* Set heap_no and the status bits. */
+		mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
+		heap_status += 1 << REC_HEAP_NO_SHIFT;
+
+		/* Read the offsets. The status bits are needed here. */
+		offsets = rec_get_offsets(rec, index, offsets,
+					  ULINT_UNDEFINED, &heap);
+
+		/* Non-leaf nodes should not have any externally
+		stored columns. */
+		ut_ad(!rec_offs_any_extern(offsets));
+
+		/* Decompress the data bytes, except node_ptr. */
+		d_stream->avail_out = rec_offs_data_size(offsets)
+			- REC_NODE_PTR_SIZE;
+
+		switch (inflate(d_stream, Z_SYNC_FLUSH)) {
+		case Z_STREAM_END:
+			goto zlib_done;
+		case Z_OK:
+		case Z_BUF_ERROR:
+			if (!d_stream->avail_out) {
+				break;
+			}
+			/* fall through */
+		default:
+			goto zlib_error;
+		}
+
+		/* Clear the node pointer in case the record
+		will be deleted and the space will be reallocated
+		to a smaller record. */
+		memset(d_stream->next_out, 0, REC_NODE_PTR_SIZE);
+		d_stream->next_out += REC_NODE_PTR_SIZE;
+
+		ut_ad(d_stream->next_out == rec_get_end(rec, offsets));
+	}
+
+	/* Decompress any trailing garbage, in case the last record was
+	allocated from an originally longer space on the free list. */
+	d_stream->avail_out = page_header_get_field(page_zip->data,
+						    PAGE_HEAP_TOP)
+		- page_offset(d_stream->next_out);
+	if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
+			  - PAGE_ZIP_START - PAGE_DIR)) {
+
+		goto zlib_error;
+	}
+
+	if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
+zlib_error:
+		inflateEnd(d_stream);
+		return(FALSE);
+	}
+
+	/* Note that d_stream->avail_out > 0 may hold here
+	if the modification log is nonempty. */
+
+zlib_done:
+	if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
+		ut_error;
+	}
+
+	{
+		page_t*	page = page_align(d_stream->next_out);
+
+		/* Clear the unused heap space on the uncompressed page. */
+		memset(d_stream->next_out, 0,
+		       page_dir_get_nth_slot(page,
+					     page_dir_get_n_slots(page) - 1)
+		       - d_stream->next_out);
+	}
+
+	page_zip->m_start = PAGE_DATA + d_stream->total_in;
+
+	/* Apply the modification log. */
+	{
+		const byte*	mod_log_ptr;
+		mod_log_ptr = page_zip_apply_log(page_zip->data
+						 + page_zip->m_start,
+						 d_stream->avail_in + 1,
+						 recs, n_dense,
+						 ULINT_UNDEFINED, heap_status,
+						 index, offsets);
+
+		if (UNIV_UNLIKELY(!mod_log_ptr)) {
+			return(FALSE);
+		}
+		page_zip->m_end = mod_log_ptr - page_zip->data;
+		ut_a(page_zip_get_trailer_len(page_zip, index, NULL)
+		     + page_zip->m_end < page_zip->size);
+	}
+
+	/* Restore the uncompressed columns in heap_no order. */
+	storage	= page_zip->data + page_zip->size
+		- n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
+
+	for (slot = 0; slot < n_dense; slot++) {
+		rec_t*		rec	= recs[slot];
+
+		offsets = rec_get_offsets(rec, index, offsets,
+					  ULINT_UNDEFINED, &heap);
+		/* Non-leaf nodes should not have any externally
+		stored columns. */
+		ut_ad(!rec_offs_any_extern(offsets));
+		storage -= REC_NODE_PTR_SIZE;
+
+		memcpy(rec_get_end(rec, offsets) - REC_NODE_PTR_SIZE,
+		       storage, REC_NODE_PTR_SIZE);
+	}
+
+	return(TRUE);
+}
+
+/**************************************************************************
+Decompress the records of a leaf node of a secondary index. */
+static
+ibool
+page_zip_decompress_sec(
+/*====================*/
+					/* out: TRUE on success,
+					FALSE on failure */
+	page_zip_des_t*	page_zip,	/* in/out: compressed page */
+	z_stream*	d_stream,	/* in/out: compressed page stream */
+	rec_t**		recs,		/* in: dense page directory
+					sorted by address */
+	ulint		n_dense,	/* in: size of recs[] */
+	dict_index_t*	index,		/* in: the index of the page */
+	ulint*		offsets)	/* in/out: temporary offsets */
+{
+	ulint	heap_status	= REC_STATUS_ORDINARY | 2 << REC_HEAP_NO_SHIFT;
+	ulint	slot;
+
+	/* Subtract the space reserved for uncompressed data. */
+	d_stream->avail_in -= n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
+
+	for (slot = 0; slot < n_dense; slot++) {
+		rec_t*	rec = recs[slot];
+
+		/* Decompress everything up to this record. */
+		d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
+			- d_stream->next_out;
+
+		if (UNIV_LIKELY(d_stream->avail_out)) {
+			switch (inflate(d_stream, Z_SYNC_FLUSH)) {
+			case Z_STREAM_END:
+				/* Apparently, n_dense has grown
+				since the time the page was last compressed. */
+				goto zlib_done;
+			case Z_OK:
+			case Z_BUF_ERROR:
+				if (!d_stream->avail_out) {
+					break;
+				}
+				/* fall through */
+			default:
+				goto zlib_error;
+			}
+		}
+
+		ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
+
+		/* Skip the REC_N_NEW_EXTRA_BYTES. */
+
+		d_stream->next_out = rec;
+
+		/* Set heap_no and the status bits. */
+		mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
+		heap_status += 1 << REC_HEAP_NO_SHIFT;
+	}
+
+	/* Decompress the data of the last record and any trailing garbage,
+	in case the last record was allocated from an originally longer space
+	on the free list. */
+	d_stream->avail_out = page_header_get_field(page_zip->data,
+						    PAGE_HEAP_TOP)
+		- page_offset(d_stream->next_out);
+	if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
+			  - PAGE_ZIP_START - PAGE_DIR)) {
+
+		goto zlib_error;
+	}
+
+	if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
+zlib_error:
+		inflateEnd(d_stream);
+		return(FALSE);
+	}
+
+	/* Note that d_stream->avail_out > 0 may hold here
+	if the modification log is nonempty. */
+
+zlib_done:
+	if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
+		ut_error;
+	}
+
+	{
+		page_t*	page = page_align(d_stream->next_out);
+
+		/* Clear the unused heap space on the uncompressed page. */
+		memset(d_stream->next_out, 0,
+		       page_dir_get_nth_slot(page,
+					     page_dir_get_n_slots(page) - 1)
+		       - d_stream->next_out);
+	}
+
+	page_zip->m_start = PAGE_DATA + d_stream->total_in;
+
+	/* Apply the modification log. */
+	{
+		const byte*	mod_log_ptr;
+		mod_log_ptr = page_zip_apply_log(page_zip->data
+						 + page_zip->m_start,
+						 d_stream->avail_in + 1,
+						 recs, n_dense,
+						 ULINT_UNDEFINED, heap_status,
+						 index, offsets);
+
+		if (UNIV_UNLIKELY(!mod_log_ptr)) {
+			return(FALSE);
+		}
+		page_zip->m_end = mod_log_ptr - page_zip->data;
+		ut_a(page_zip_get_trailer_len(page_zip, index, NULL)
+		     + page_zip->m_end < page_zip->size);
+	}
+
+	/* There are no uncompressed columns on leaf pages of
+	secondary indexes. */
+
+	return(TRUE);
+}
+
+/**************************************************************************
+Compress the records of a leaf node of a clustered index. */
+static
+ibool
+page_zip_decompress_clust(
+/*======================*/
+					/* out: TRUE on success,
+					FALSE on failure */
+	page_zip_des_t*	page_zip,	/* in/out: compressed page */
+	z_stream*	d_stream,	/* in/out: compressed page stream */
+	rec_t**		recs,		/* in: dense page directory
+					sorted by address */
+	ulint		n_dense,	/* in: size of recs[] */
+	dict_index_t*	index,		/* in: the index of the page */
+	ulint		trx_id_col,	/* index of the trx_id column */
+	ulint*		offsets,	/* in/out: temporary offsets */
+	mem_heap_t*	heap)		/* in: temporary memory heap */
+{
+	int		err;
+	ulint		slot;
+	ulint		heap_status	= REC_STATUS_ORDINARY
+		| 2 << REC_HEAP_NO_SHIFT;
+	const byte*	storage;
+	const byte*	externs;
+
+	/* Subtract the space reserved for uncompressed data. */
+	d_stream->avail_in -= n_dense * (PAGE_ZIP_DIR_SLOT_SIZE
+					 + DATA_TRX_ID_LEN
+					 + DATA_ROLL_PTR_LEN);
+
+	/* Decompress the records in heap_no order. */
+	for (slot = 0; slot < n_dense; slot++) {
+		rec_t*	rec	= recs[slot];
+
+		d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
+			- d_stream->next_out;
+
+		ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
+		      - PAGE_ZIP_START - PAGE_DIR);
+		err = inflate(d_stream, Z_SYNC_FLUSH);
+		switch (err) {
+		case Z_STREAM_END:
+			/* Apparently, n_dense has grown
+			since the time the page was last compressed. */
+			goto zlib_done;
+		case Z_OK:
+		case Z_BUF_ERROR:
+			if (UNIV_LIKELY(!d_stream->avail_out)) {
+				break;
+			}
+			/* fall through */
+		default:
+			goto zlib_error;
+		}
+
+		ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
+		/* Prepare to decompress the data bytes. */
+		d_stream->next_out = rec;
+		/* Set heap_no and the status bits. */
+		mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
+		heap_status += 1 << REC_HEAP_NO_SHIFT;
+
+		/* Read the offsets. The status bits are needed here. */
+		offsets = rec_get_offsets(rec, index, offsets,
+					  ULINT_UNDEFINED, &heap);
+
+		/* This is a leaf page in a clustered index. */
+		ulint	i;
+
+		/* Check if there are any externally stored columns.
+		For each externally stored column, restore the
+		BTR_EXTERN_FIELD_REF separately. */
+
+		for (i = 0; i < rec_offs_n_fields(offsets); i++) {
+			ulint	len;
+			byte*	dst;
+
+			if (UNIV_UNLIKELY(i == trx_id_col)) {
+				/* Skip trx_id and roll_ptr */
+				dst = rec_get_nth_field(rec, offsets, i, &len);
+				if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN
+						  + DATA_ROLL_PTR_LEN)
+				    || rec_offs_nth_extern(offsets, i)) {
+
+					goto zlib_error;
+				}
+
+				d_stream->avail_out = dst - d_stream->next_out;
+
+				switch (inflate(d_stream, Z_SYNC_FLUSH)) {
+				case Z_STREAM_END:
+				case Z_OK:
+				case Z_BUF_ERROR:
+					if (!d_stream->avail_out) {
+						break;
+					}
+					/* fall through */
+				default:
+					goto zlib_error;
+				}
+
+				ut_ad(d_stream->next_out == dst);
+
+				d_stream->next_out += DATA_TRX_ID_LEN
+					+ DATA_ROLL_PTR_LEN;
+			} else if (rec_offs_nth_extern(offsets, i)) {
+				dst = rec_get_nth_field(rec, offsets, i, &len);
+				ut_ad(len > BTR_EXTERN_FIELD_REF_SIZE);
+				dst += len - BTR_EXTERN_FIELD_REF_SIZE;
+
+				d_stream->avail_out = dst - d_stream->next_out;
+				switch (inflate(d_stream,
+						Z_SYNC_FLUSH)) {
+				case Z_STREAM_END:
+				case Z_OK:
+				case Z_BUF_ERROR:
+					if (!d_stream->avail_out) {
+						break;
+					}
+					/* fall through */
+				default:
+					goto zlib_error;
+				}
+
+				ut_ad(d_stream->next_out == dst);
+
+				/* Reserve space for the data at
+				the end of the space reserved for
+				the compressed data and the
+				page modification log. */
+
+				if (UNIV_UNLIKELY
+				    (d_stream->avail_in
+				     <= BTR_EXTERN_FIELD_REF_SIZE)) {
+					/* out of space */
+					goto zlib_error;
+				}
+
+				/* Clear the BLOB pointer in case
+				the record will be deleted and the
+				space will not be reused.  Note that
+				the final initialization of the BLOB
+				pointers (copying from "externs"
+				or clearing) will have to take place
+				only after the page modification log
+				has been applied.  Otherwise, we
+				could end up with an uninitialized
+				BLOB pointer when a record is deleted,
+				reallocated and deleted. */
+				memset(d_stream->next_out, 0,
+				       BTR_EXTERN_FIELD_REF_SIZE);
+				d_stream->next_out
+					+= BTR_EXTERN_FIELD_REF_SIZE;
+			}
+		}
+
+		/* Decompress the last bytes of the record. */
+		d_stream->avail_out = rec_get_end(rec, offsets)
+			- d_stream->next_out;
+
+		switch (inflate(d_stream, Z_SYNC_FLUSH)) {
+		case Z_STREAM_END:
+		case Z_OK:
+		case Z_BUF_ERROR:
+			if (!d_stream->avail_out) {
+				break;
+			}
+			/* fall through */
+		default:
+			goto zlib_error;
+		}
+	}
+
+	/* Decompress any trailing garbage, in case the last record was
+	allocated from an originally longer space on the free list. */
+	d_stream->avail_out = page_header_get_field(page_zip->data,
+						    PAGE_HEAP_TOP)
+		- page_offset(d_stream->next_out);
+	if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
+			  - PAGE_ZIP_START - PAGE_DIR)) {
+
+		goto zlib_error;
+	}
+
+	if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
+zlib_error:
+		inflateEnd(d_stream);
+		return(FALSE);
+	}
+
+	/* Note that d_stream->avail_out > 0 may hold here
+	if the modification log is nonempty. */
+
+zlib_done:
+	if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
+		ut_error;
+	}
+
+	{
+		page_t*	page = page_align(d_stream->next_out);
+
+		/* Clear the unused heap space on the uncompressed page. */
+		memset(d_stream->next_out, 0,
+		       page_dir_get_nth_slot(page,
+					     page_dir_get_n_slots(page) - 1)
+		       - d_stream->next_out);
+	}
+
+	page_zip->m_start = PAGE_DATA + d_stream->total_in;
+
+	/* Apply the modification log. */
+	{
+		const byte*	mod_log_ptr;
+		mod_log_ptr = page_zip_apply_log(page_zip->data
+						 + page_zip->m_start,
+						 d_stream->avail_in + 1,
+						 recs, n_dense,
+						 trx_id_col, heap_status,
+						 index, offsets);
+
+		if (UNIV_UNLIKELY(!mod_log_ptr)) {
+			return(FALSE);
+		}
+		page_zip->m_end = mod_log_ptr - page_zip->data;
+		ut_a(page_zip_get_trailer_len(page_zip, index, NULL)
+		     + page_zip->m_end < page_zip->size);
+	}
+
+	storage = page_zip->data + page_zip->size
+		- n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
+
+	externs = storage - n_dense
+		* (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
+
+	/* Restore the uncompressed columns in heap_no order. */
+
+	for (slot = 0; slot < n_dense; slot++) {
+		ulint	i;
+		ulint	len;
+		byte*	dst;
+		rec_t*	rec	= recs[slot];
+		ibool	exists	= !page_zip_dir_find_free(
+			page_zip, page_offset(rec));
+		offsets = rec_get_offsets(rec, index, offsets,
+					  ULINT_UNDEFINED, &heap);
+
+		dst = rec_get_nth_field(rec, offsets,
+					trx_id_col, &len);
+		ut_ad(len >= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
+		storage -= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
+		memcpy(dst, storage,
+		       DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
+
+		/* Check if there are any externally stored
+		columns in this record.  For each externally
+		stored column, restore or clear the
+		BTR_EXTERN_FIELD_REF. */
+
+		for (i = 0; i < rec_offs_n_fields(offsets); i++) {
+			if (!rec_offs_nth_extern(offsets, i)) {
+				continue;
+			}
+			dst = rec_get_nth_field(rec, offsets, i, &len);
+			ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
+			dst += len - BTR_EXTERN_FIELD_REF_SIZE;
+
+			if (UNIV_LIKELY(exists)) {
+				/* Existing record:
+				restore the BLOB pointer */
+				externs -= BTR_EXTERN_FIELD_REF_SIZE;
+
+				memcpy(dst, externs,
+				       BTR_EXTERN_FIELD_REF_SIZE);
+
+				page_zip->n_blobs++;
+			} else {
+				/* Deleted record:
+				clear the BLOB pointer */
+				memset(dst, 0,
+				       BTR_EXTERN_FIELD_REF_SIZE);
+			}
+		}
+	}
+
+	return(TRUE);
+}
+
 /**************************************************************************
 Decompress a page.  This function should tolerate errors on the compressed
 page.  Instead of letting assertions fail, it will return FALSE if an
@@ -1645,14 +2218,10 @@ page_zip_decompress(
 	z_stream	d_stream;
 	dict_index_t*	index	= NULL;
 	rec_t**		recs;	/* dense page directory, sorted by address */
-	ulint		slot;
-	ulint		heap_status;/* heap_no and status bits */
 	ulint		n_dense;/* number of user records on the page */
 	ulint		trx_id_col = ULINT_UNDEFINED;
 	mem_heap_t*	heap;
-	ulint*		offsets	= NULL;
-	ulint		info_bits = 0;
-	const byte*	storage;
+	ulint*		offsets;
 
 	ut_ad(page_zip_simple_validate(page_zip));
 
@@ -1674,9 +2243,9 @@ page_zip_decompress(
 	memcpy(page, page_zip->data, PAGE_DATA);
 
 	/* Copy the page directory. */
-	if (UNIV_UNLIKELY
-	    (!page_zip_dir_decode(page_zip, page,
-				  recs, recs + n_dense, n_dense))) {
+	if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs,
+					       recs + n_dense, n_dense))) {
+zlib_error:
 		mem_heap_free(heap);
 		return(FALSE);
 	}
@@ -1729,378 +2298,67 @@ page_zip_decompress(
 	}
 
 	/* Decompress the user records. */
+	page_zip->n_blobs = 0;
 	d_stream.next_out = page + PAGE_ZIP_START;
 
 	{
-		/* Pre-allocate the offsets
-		for rec_get_offsets_reverse(). */
-		ulint	n;
-
-		if (page_is_leaf(page)) {
-			n = dict_index_get_n_fields(index);
-			heap_status = REC_STATUS_ORDINARY
-				| 2 << REC_HEAP_NO_SHIFT;
-
-			/* Subtract the space reserved
-			for uncompressed data. */
-			if (trx_id_col != ULINT_UNDEFINED) {
-				d_stream.avail_in -= n_dense
-					* (PAGE_ZIP_DIR_SLOT_SIZE
-					   + DATA_TRX_ID_LEN
-					   + DATA_ROLL_PTR_LEN);
-			} else {
-				d_stream.avail_in -= n_dense
-					* PAGE_ZIP_DIR_SLOT_SIZE;
-			}
-		} else {
-			n = dict_index_get_n_unique_in_tree(index) + 1;
-			heap_status = REC_STATUS_NODE_PTR
-				| 2 << REC_HEAP_NO_SHIFT;
-
-			if (UNIV_UNLIKELY
-			    (mach_read_from_4(page + FIL_PAGE_PREV)
-			     == FIL_NULL)) {
-				info_bits = REC_INFO_MIN_REC_FLAG;
-			}
-
-			/* Subtract the space reserved
-			for uncompressed data. */
-			d_stream.avail_in -= n_dense
-				* (PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE);
-		}
-
-		n += 1 + REC_OFFS_HEADER_SIZE;
+		/* Pre-allocate the offsets for rec_get_offsets_reverse(). */
+		ulint	n = 1 + 1/* node ptr */ + REC_OFFS_HEADER_SIZE
+			+ dict_index_get_n_fields(index);
 		offsets = mem_heap_alloc(heap, n * sizeof(ulint));
 		*offsets = n;
 	}
 
 	/* Decompress the records in heap_no order. */
-	for (slot = 0; slot < n_dense; slot++) {
-		rec_t*		rec	= recs[slot];
+	if (!page_is_leaf(page)) {
+		/* This is a node pointer page. */
+		ulint	info_bits;
 
-		d_stream.avail_out = rec - REC_N_NEW_EXTRA_BYTES
-			- d_stream.next_out;
-
-		ut_ad(d_stream.avail_out < UNIV_PAGE_SIZE
-		      - PAGE_ZIP_START - PAGE_DIR);
-		switch (inflate(&d_stream, Z_SYNC_FLUSH)) {
-		case Z_STREAM_END:
-			/* Apparently, n_dense has grown
-			since the time the page was last compressed. */
-			goto zlib_done;
-		case Z_OK:
-		case Z_BUF_ERROR:
-			if (!d_stream.avail_out) {
-				break;
-			}
-		default:
-			goto zlib_error;
-		}
-
-		ut_ad(d_stream.next_out == rec - REC_N_NEW_EXTRA_BYTES);
-		/* Prepare to decompress the data bytes. */
-		d_stream.next_out = rec;
-		/* Set heap_no and the status bits. */
-		mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
-		heap_status += 1 << REC_HEAP_NO_SHIFT;
-
-		/* Read the offsets. The status bits are needed here. */
-		offsets = rec_get_offsets(rec, index, offsets,
-					  ULINT_UNDEFINED, &heap);
-
-		if (!page_is_leaf(page)) {
-			/* Non-leaf nodes should not have any externally
-			stored columns. */
-			ut_ad(!rec_offs_any_extern(offsets));
-
-			/* Decompress the data bytes, except node_ptr. */
-			d_stream.avail_out = rec_offs_data_size(offsets)
-				- REC_NODE_PTR_SIZE;
-
-			switch (inflate(&d_stream, Z_SYNC_FLUSH)) {
-			case Z_STREAM_END:
-			case Z_OK:
-			case Z_BUF_ERROR:
-				if (!d_stream.avail_out) {
-					break;
-				}
-				/* fall through */
-			default:
-				goto zlib_error;
-			}
-
-			/* Clear the node pointer in case the record
-			will be deleted and the space will be reallocated
-			to a smaller record. */
-			memset(d_stream.next_out, 0, REC_NODE_PTR_SIZE);
-			d_stream.next_out += REC_NODE_PTR_SIZE;
-		} else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
-			/* This is a leaf page in a non-clustered index. */
-			goto decompress_tail;
-		} else {
-			/* This is a leaf page in a clustered index. */
-			ulint	i;
-
-			/* Check if there are any externally stored columns.
-			For each externally stored column, restore the
-			BTR_EXTERN_FIELD_REF separately. */
-
-			for (i = 0; i < rec_offs_n_fields(offsets); i++) {
-				ulint	len;
-				byte*	dst;
-
-				if (UNIV_UNLIKELY(i == trx_id_col)) {
-					/* Skip trx_id and roll_ptr */
-					dst = rec_get_nth_field(rec, offsets,
-								i, &len);
-					if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN
-							  + DATA_ROLL_PTR_LEN)
-					    || rec_offs_nth_extern(offsets,
-								   i)) {
-
-						goto zlib_error;
-					}
-
-					d_stream.avail_out = dst
-						- d_stream.next_out;
-
-					switch (inflate(&d_stream,
-							Z_SYNC_FLUSH)) {
-					case Z_STREAM_END:
-					case Z_OK:
-					case Z_BUF_ERROR:
-						if (!d_stream.avail_out) {
-							break;
-						}
-						/* fall through */
-					default:
-						goto zlib_error;
-					}
-
-					ut_ad(d_stream.next_out == dst);
-
-					d_stream.next_out += DATA_TRX_ID_LEN
-						+ DATA_ROLL_PTR_LEN;
-				} else if (rec_offs_nth_extern(offsets, i)) {
-					dst = rec_get_nth_field(rec, offsets,
-								i, &len);
-					ut_ad(len > BTR_EXTERN_FIELD_REF_SIZE);
-					dst += len - BTR_EXTERN_FIELD_REF_SIZE;
-
-					d_stream.avail_out = dst
-						- d_stream.next_out;
-					switch (inflate(&d_stream,
-							Z_SYNC_FLUSH)) {
-					case Z_STREAM_END:
-					case Z_OK:
-					case Z_BUF_ERROR:
-						if (!d_stream.avail_out) {
-							break;
-						}
-						/* fall through */
-					default:
-						goto zlib_error;
-					}
-
-					ut_ad(d_stream.next_out == dst);
-
-					/* Reserve space for the data at
-					the end of the space reserved for
-					the compressed data and the
-					page modification log. */
-
-					if (UNIV_UNLIKELY
-					    (d_stream.avail_in
-					     <= BTR_EXTERN_FIELD_REF_SIZE)) {
-						/* out of space */
-						goto zlib_error;
-					}
-
-					/* Clear the BLOB pointer in case
-					the record will be deleted and the
-					space will not be reused.  Note that
-					the final initialization of the BLOB
-					pointers (copying from "externs"
-					or clearing) will have to take place
-					only after the page modification log
-					has been applied.  Otherwise, we
-					could end up with an uninitialized
-					BLOB pointer when a record is deleted,
-					reallocated and deleted. */
-					memset(d_stream.next_out, 0,
-					       BTR_EXTERN_FIELD_REF_SIZE);
-					d_stream.next_out
-						+= BTR_EXTERN_FIELD_REF_SIZE;
-				}
-			}
-
-decompress_tail:
-			/* Decompress the last bytes of the record. */
-			d_stream.avail_out = rec_get_end(rec, offsets)
-				- d_stream.next_out;
-
-			switch (inflate(&d_stream, Z_SYNC_FLUSH)) {
-			case Z_STREAM_END:
-			case Z_OK:
-			case Z_BUF_ERROR:
-				if (!d_stream.avail_out) {
-					break;
-				}
-				/* fall through */
-			default:
-				goto zlib_error;
-			}
-		}
-
-		ut_ad(d_stream.next_out == rec_get_end(rec, offsets));
-	}
-
-	/* Decompress any trailing garbage, in case the last record was
-	allocated from an originally longer space on the free list. */
-	d_stream.avail_out = page_header_get_field(page, PAGE_HEAP_TOP)
-		- (d_stream.next_out - page);
-	if (UNIV_UNLIKELY(d_stream.avail_out > UNIV_PAGE_SIZE
-			  - PAGE_ZIP_START - PAGE_DIR)) {
-
-		goto zlib_error;
-	}
-
-	if (UNIV_UNLIKELY(inflate(&d_stream, Z_FINISH) != Z_STREAM_END)) {
-zlib_error:
-		inflateEnd(&d_stream);
-		goto err_exit;
-	}
-
-	/* Note that d_stream.avail_out > 0 may hold here
-	if the modification log is nonempty. */
-
-zlib_done:
-	if (UNIV_UNLIKELY(inflateEnd(&d_stream) != Z_OK)) {
-		ut_error;
-	}
-
-	ut_ad(page_zip->data + PAGE_DATA + d_stream.total_in
-	      == d_stream.next_in);
-
-	/* Clear the unused heap space on the uncompressed page. */
-	memset(d_stream.next_out, 0,
-	       page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1)
-	       - d_stream.next_out);
-
-	/* The dense directory excludes the infimum and supremum records. */
-	n_dense = page_dir_get_n_heap(page) - 2;
-
-	page_zip->n_blobs = 0;
-	page_zip->m_start = PAGE_DATA + d_stream.total_in;
-
-	/* Apply the modification log. */
-	{
-		const byte*	mod_log_ptr;
-		mod_log_ptr = page_zip_apply_log(page_zip->data
-						 + page_zip->m_start,
-						 d_stream.avail_in + 1,
-						 recs, n_dense,
-						 trx_id_col, heap_status,
-						 index, offsets);
-
-		if (UNIV_UNLIKELY(!mod_log_ptr)) {
+		if (UNIV_UNLIKELY
+		    (!page_zip_decompress_node_ptrs(page_zip, &d_stream,
+						    recs, n_dense, index,
+						    offsets, heap))) {
 			goto err_exit;
 		}
-		page_zip->m_end = mod_log_ptr - page_zip->data;
-		ut_a(page_zip_get_trailer_len(page_zip, index, NULL)
-		     + page_zip->m_end < page_zip->size);
-	}
 
-	if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip, page,
-						    info_bits))) {
+		info_bits = mach_read_from_4(page + FIL_PAGE_PREV) == FIL_NULL
+			? REC_INFO_MIN_REC_FLAG : 0;
+
+		if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip, page,
+							    info_bits))) {
+			goto err_exit;
+		}
+	} else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
+		/* This is a leaf page in a secondary index. */
+		if (UNIV_UNLIKELY(!page_zip_decompress_sec(page_zip, &d_stream,
+							   recs, n_dense,
+							   index, offsets))) {
+			goto err_exit;
+		}
+
+		if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
+							    page, 0))) {
 err_exit:
-		page_zip_fields_free(index);
-		mem_heap_free(heap);
-		return(FALSE);
-	}
-
-	/* Copy the uncompressed fields. */
-
-	storage = page_zip->data + page_zip->size
-		- n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
-
-	if (UNIV_UNLIKELY(!n_dense)) {
-		goto recs_done;
-	}
-
-	/* Restore the uncompressed columns in heap_no order. */
-
-	if (page_is_leaf(page)) {
-		const byte*	externs	= storage - n_dense
-			* (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
-
-		do {
-			ulint	i;
-			ulint	len;
-			byte*	dst;
-			rec_t*	rec	= *recs++;
-			ibool	exists	= !page_zip_dir_find_free(
-				page_zip, page_offset(rec));
-			offsets = rec_get_offsets(rec, index, offsets,
-						  ULINT_UNDEFINED, &heap);
-
-			if (UNIV_UNLIKELY(trx_id_col != ULINT_UNDEFINED)) {
-				dst = rec_get_nth_field(rec, offsets,
-							trx_id_col, &len);
-				ut_ad(len >= DATA_TRX_ID_LEN
-				      + DATA_ROLL_PTR_LEN);
-				storage -= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
-				memcpy(dst, storage,
-				       DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
-			}
-
-			/* Check if there are any externally stored
-			columns in this record.  For each externally
-			stored column, restore or clear the
-			BTR_EXTERN_FIELD_REF. */
-
-			for (i = 0; i < rec_offs_n_fields(offsets); i++) {
-				if (!rec_offs_nth_extern(offsets, i)) {
-					continue;
-				}
-				dst = rec_get_nth_field(rec, offsets, i, &len);
-				ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
-				dst += len - BTR_EXTERN_FIELD_REF_SIZE;
-
-				if (UNIV_LIKELY(exists)) {
-					/* Existing record:
-					restore the BLOB pointer */
-					externs -= BTR_EXTERN_FIELD_REF_SIZE;
-
-					memcpy(dst, externs,
-					       BTR_EXTERN_FIELD_REF_SIZE);
-
-					page_zip->n_blobs++;
-				} else {
-					/* Deleted record:
-					clear the BLOB pointer */
-					memset(dst, 0,
-					       BTR_EXTERN_FIELD_REF_SIZE);
-				}
-			}
-		} while (--n_dense);
+			page_zip_fields_free(index);
+			mem_heap_free(heap);
+			return(FALSE);
+		}
 	} else {
-		do {
-			rec_t*	rec	= *recs++;
+		/* This is a leaf page in a clustered index. */
+		if (UNIV_UNLIKELY(!page_zip_decompress_clust(page_zip,
+							     &d_stream, recs,
+							     n_dense, index,
+							     trx_id_col,
+							     offsets, heap))) {
+			goto err_exit;
+		}
 
-			offsets = rec_get_offsets(rec, index, offsets,
-						  ULINT_UNDEFINED, &heap);
-			/* Non-leaf nodes should not have any externally
-			stored columns. */
-			ut_ad(!rec_offs_any_extern(offsets));
-			storage -= REC_NODE_PTR_SIZE;
-
-			memcpy(rec_get_end(rec, offsets) - REC_NODE_PTR_SIZE,
-			       storage, REC_NODE_PTR_SIZE);
-		} while (--n_dense);
+		if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
+							    page, 0))) {
+			goto err_exit;
+		}
 	}
 
-recs_done:
 	ut_a(page_is_comp(page));
 
 	page_zip_fields_free(index);