summaryrefslogtreecommitdiff
path: root/storage/xtradb/row/row0ext.cc
blob: 32b78391d6a66297aa80d7efbcfb9ffa10677476 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*****************************************************************************

Copyright (c) 2006, 2013, Oracle and/or its affiliates. All Rights Reserved.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA

*****************************************************************************/

/**************************************************//**
@file row/row0ext.cc
Caching of externally stored column prefixes

Created September 2006 Marko Makela
*******************************************************/

#include "row0ext.h"

#ifdef UNIV_NONINL
#include "row0ext.ic"
#endif

#include "btr0cur.h"

/********************************************************************//**
Fills the column prefix cache of an externally stored column. */
static
void
row_ext_cache_fill(
/*===============*/
	row_ext_t*	ext,	/*!< in/out: column prefix cache */
	ulint		i,	/*!< in: index of ext->ext[] */
	ulint		zip_size,/*!< compressed page size in bytes, or 0 */
	const dfield_t*	dfield)	/*!< in: data field */
{
	const byte*	field	= static_cast<const byte*>(
					dfield_get_data(dfield));
	ulint		f_len	= dfield_get_len(dfield);
	byte*		buf	= ext->buf + i * ext->max_len;

	ut_ad(ext->max_len > 0);
	ut_ad(i < ext->n_ext);
	ut_ad(dfield_is_ext(dfield));
	ut_a(f_len >= BTR_EXTERN_FIELD_REF_SIZE);

	if (UNIV_UNLIKELY(!memcmp(field_ref_zero,
				  field + f_len - BTR_EXTERN_FIELD_REF_SIZE,
				  BTR_EXTERN_FIELD_REF_SIZE))) {
		/* The BLOB pointer is not set: we cannot fetch it */
		ext->len[i] = 0;
	} else {
		if (ext->max_len == REC_VERSION_56_MAX_INDEX_COL_LEN
		    && f_len > BTR_EXTERN_FIELD_REF_SIZE) {
			/* In this case, the field is in B format or beyond,
			(refer to the definition of row_ext_t.max_len)
			and the field is already fill with prefix, otherwise
			f_len would be BTR_EXTERN_FIELD_REF_SIZE.
			So there is no need to re-read the prefix externally,
			but just copy the local prefix to buf. Please note
			if the ext->len[i] is zero, it means an error
			as above. */
			memcpy(buf, field, f_len - BTR_EXTERN_FIELD_REF_SIZE);
			ext->len[i] = f_len - BTR_EXTERN_FIELD_REF_SIZE;
		} else {
			/* Fetch at most ext->max_len of the column.
			The column should be non-empty.  However,
			trx_rollback_or_clean_all_recovered() may try to
			access a half-deleted BLOB if the server previously
			crashed during the execution of
			btr_free_externally_stored_field(). */
			ext->len[i] = btr_copy_externally_stored_field_prefix(
				buf, ext->max_len, zip_size, field, f_len);
		}
	}
}

/********************************************************************//**
Creates a cache of column prefixes of externally stored columns.
@return	own: column prefix cache */
UNIV_INTERN
row_ext_t*
row_ext_create(
/*===========*/
	ulint		n_ext,	/*!< in: number of externally stored columns */
	const ulint*	ext,	/*!< in: col_no's of externally stored columns
				in the InnoDB table object, as reported by
				dict_col_get_no(); NOT relative to the records
				in the clustered index */
	ulint		flags,	/*!< in: table->flags */
	const dtuple_t*	tuple,	/*!< in: data tuple containing the field
				references of the externally stored
				columns; must be indexed by col_no;
				the clustered index record must be
				covered by a lock or a page latch
				to prevent deletion (rollback or purge). */
	mem_heap_t*	heap)	/*!< in: heap where created */
{
	ulint		i;
	ulint		zip_size = dict_tf_get_zip_size(flags);

	row_ext_t*	ret;

	ut_ad(n_ext > 0);

	ret = static_cast<row_ext_t*>(
		mem_heap_alloc(heap,
			       (sizeof *ret) + (n_ext - 1) * sizeof ret->len));

	ut_ad(ut_is_2pow(zip_size));
	ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX);

	ret->n_ext = n_ext;
	ret->ext = ext;
	ret->max_len = DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(flags);

	ret->buf = static_cast<byte*>(
		mem_heap_alloc(heap, n_ext * ret->max_len));

#ifdef UNIV_DEBUG
	memset(ret->buf, 0xaa, n_ext * ret->max_len);
	UNIV_MEM_ALLOC(ret->buf, n_ext * ret->max_len);
#endif

	/* Fetch the BLOB prefixes */
	for (i = 0; i < n_ext; i++) {
		const dfield_t*	dfield;

		dfield = dtuple_get_nth_field(tuple, ext[i]);
		row_ext_cache_fill(ret, i, zip_size, dfield);
	}

	return(ret);
}