~drizzle-trunk/drizzle/development

641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1
/*****************************************************************************
2
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
3
Copyright (C) 1994, 2010, Innobase Oy. All Rights Reserved.
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
4
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
8
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13
You should have received a copy of the GNU General Public License along with
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
16
17
*****************************************************************************/
18
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
19
/********************************************************************//**
20
@file rem/rem0rec.c
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
21
Record manager
22
23
Created 5/30/1994 Heikki Tuuri
24
*************************************************************************/
25
26
#include "rem0rec.h"
27
28
#ifdef UNIV_NONINL
29
#include "rem0rec.ic"
30
#endif
31
32
#include "mtr0mtr.h"
33
#include "mtr0log.h"
34
35
/*			PHYSICAL RECORD (OLD STYLE)
36
			===========================
37
38
The physical record, which is the data type of all the records
39
found in index pages of the database, has the following format
40
(lower addresses and more significant bits inside a byte are below
41
represented on a higher text line):
42
43
| offset of the end of the last field of data, the most significant
44
  bit is set to 1 if and only if the field is SQL-null,
45
  if the offset is 2-byte, then the second most significant
46
  bit is set to 1 if the field is stored on another page:
47
  mostly this will occur in the case of big BLOB fields |
48
...
49
| offset of the end of the first field of data + the SQL-null bit |
50
| 4 bits used to delete mark a record, and mark a predefined
51
  minimum record in alphabetical order |
52
| 4 bits giving the number of records owned by this record
53
  (this term is explained in page0page.h) |
54
| 13 bits giving the order number of this record in the
55
  heap of the index page |
56
| 10 bits giving the number of fields in this record |
57
| 1 bit which is set to 1 if the offsets above are given in
58
  one byte format, 0 if in two byte format |
59
| two bytes giving an absolute pointer to the next record in the page |
60
ORIGIN of the record
61
| first field of data |
62
...
63
| last field of data |
64
65
The origin of the record is the start address of the first field
66
of data. The offsets are given relative to the origin.
67
The offsets of the data fields are stored in an inverted
68
order because then the offset of the first fields are near the
69
origin, giving maybe a better processor cache hit rate in searches.
70
71
The offsets of the data fields are given as one-byte
72
(if there are less than 127 bytes of data in the record)
73
or two-byte unsigned integers. The most significant bit
74
is not part of the offset, instead it indicates the SQL-null
75
if the bit is set to 1. */
76
77
/*			PHYSICAL RECORD (NEW STYLE)
78
			===========================
79
80
The physical record, which is the data type of all the records
81
found in index pages of the database, has the following format
82
(lower addresses and more significant bits inside a byte are below
83
represented on a higher text line):
84
85
| length of the last non-null variable-length field of data:
86
  if the maximum length is 255, one byte; otherwise,
87
  0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
88
  length=128..16383, extern storage flag) |
89
...
90
| length of first variable-length field of data |
91
| SQL-null flags (1 bit per nullable field), padded to full bytes |
92
| 4 bits used to delete mark a record, and mark a predefined
93
  minimum record in alphabetical order |
94
| 4 bits giving the number of records owned by this record
95
  (this term is explained in page0page.h) |
96
| 13 bits giving the order number of this record in the
97
  heap of the index page |
98
| 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
99
  010=infimum, 011=supremum, 1xx=reserved |
100
| two bytes giving a relative pointer to the next record in the page |
101
ORIGIN of the record
102
| first field of data |
103
...
104
| last field of data |
105
106
The origin of the record is the start address of the first field
107
of data. The offsets are given relative to the origin.
108
The offsets of the data fields are stored in an inverted
109
order because then the offset of the first fields are near the
110
origin, giving maybe a better processor cache hit rate in searches.
111
112
The offsets of the data fields are given as one-byte
113
(if there are less than 127 bytes of data in the record)
114
or two-byte unsigned integers. The most significant bit
115
is not part of the offset, instead it indicates the SQL-null
116
if the bit is set to 1. */
117
118
/* CANONICAL COORDINATES. A record can be seen as a single
119
string of 'characters' in the following way: catenate the bytes
120
in each field, in the order of fields. An SQL-null field
121
is taken to be an empty sequence of bytes. Then after
122
the position of each field insert in the string
123
the 'character' <FIELD-END>, except that after an SQL-null field
124
insert <NULL-FIELD-END>. Now the ordinal position of each
125
byte in this canonical string is its canonical coordinate.
126
So, for the record ("AA", SQL-NULL, "BB", ""), the canonical
127
string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>".
128
We identify prefixes (= initial segments) of a record
129
with prefixes of the canonical string. The canonical
130
length of the prefix is the length of the corresponding
131
prefix of the canonical string. The canonical length of
132
a record is the length of its canonical string.
133
134
For example, the maximal common prefix of records
135
("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C")
136
is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical
137
length is 5.
138
139
A complete-field prefix of a record is a prefix which ends at the
140
end of some field (containing also <FIELD-END>).
141
A record is a complete-field prefix of another record, if
142
the corresponding canonical strings have the same property. */
143
144
/* this is used to fool compiler in rec_validate */
145
UNIV_INTERN ulint	rec_dummy;
146
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
147
/***************************************************************//**
148
Validates the consistency of an old-style physical record.
149
@return	TRUE if ok */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
150
static
151
ibool
152
rec_validate_old(
153
/*=============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
154
	const rec_t*	rec);	/*!< in: physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
155
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
156
/******************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
157
Determine how many of the first n columns in a compact
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
158
physical record are stored externally.
159
@return	number of externally stored columns */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
160
UNIV_INTERN
161
ulint
162
rec_get_n_extern_new(
163
/*=================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
164
	const rec_t*	rec,	/*!< in: compact physical record */
165
	dict_index_t*	index,	/*!< in: record descriptor */
166
	ulint		n)	/*!< in: number of columns to scan */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
167
{
168
	const byte*	nulls;
169
	const byte*	lens;
170
	dict_field_t*	field;
171
	ulint		null_mask;
172
	ulint		n_extern;
173
	ulint		i;
174
175
	ut_ad(dict_table_is_comp(index->table));
176
	ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
177
	ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
178
179
	if (n == ULINT_UNDEFINED) {
180
		n = dict_index_get_n_fields(index);
181
	}
182
183
	nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
184
	lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
185
	null_mask = 1;
186
	n_extern = 0;
187
	i = 0;
188
189
	/* read the lengths of fields 0..n */
190
	do {
191
		ulint	len;
192
193
		field = dict_index_get_nth_field(index, i);
194
		if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
195
			/* nullable field => read the null flag */
196
197
			if (UNIV_UNLIKELY(!(byte) null_mask)) {
198
				nulls--;
199
				null_mask = 1;
200
			}
201
202
			if (*nulls & null_mask) {
203
				null_mask <<= 1;
204
				/* No length is stored for NULL fields. */
205
				continue;
206
			}
207
			null_mask <<= 1;
208
		}
209
210
		if (UNIV_UNLIKELY(!field->fixed_len)) {
211
			/* Variable-length field: read the length */
212
			const dict_col_t*	col
213
				= dict_field_get_col(field);
214
			len = *lens--;
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
215
			/* If the maximum length of the field is up
216
			to 255 bytes, the actual length is always
217
			stored in one byte. If the maximum length is
218
			more than 255 bytes, the actual length is
219
			stored in one byte for 0..127.  The length
220
			will be encoded in two bytes when it is 128 or
221
			more, or when the field is stored externally. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
222
			if (UNIV_UNLIKELY(col->len > 255)
223
			    || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
224
				if (len & 0x80) {
225
					/* 1exxxxxxx xxxxxxxx */
226
					if (len & 0x40) {
227
						n_extern++;
228
					}
229
					lens--;
230
				}
231
			}
232
		}
233
	} while (++i < n);
234
235
	return(n_extern);
236
}
237
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
238
/******************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
239
Determine the offset to each field in a leaf-page record
240
in ROW_FORMAT=COMPACT.  This is a special case of
241
rec_init_offsets() and rec_get_offsets_func(). */
242
UNIV_INTERN
243
void
244
rec_init_offsets_comp_ordinary(
245
/*===========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
246
	const rec_t*		rec,	/*!< in: physical record in
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
247
					ROW_FORMAT=COMPACT */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
248
	ulint			extra,	/*!< in: number of bytes to reserve
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
249
					between the record header and
250
					the data payload
251
					(usually REC_N_NEW_EXTRA_BYTES) */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
252
	const dict_index_t*	index,	/*!< in: record descriptor */
253
	ulint*			offsets)/*!< in/out: array of offsets;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
254
					in: n=rec_offs_n_fields(offsets) */
255
{
256
	ulint		i		= 0;
257
	ulint		offs		= 0;
258
	ulint		any_ext		= 0;
259
	const byte*	nulls		= rec - (extra + 1);
260
	const byte*	lens		= nulls
261
		- UT_BITS_IN_BYTES(index->n_nullable);
262
	dict_field_t*	field;
263
	ulint		null_mask	= 1;
264
265
#ifdef UNIV_DEBUG
266
	/* We cannot invoke rec_offs_make_valid() here, because it can hold
267
	that extra != REC_N_NEW_EXTRA_BYTES.  Similarly, rec_offs_validate()
268
	will fail in that case, because it invokes rec_get_status(). */
269
	offsets[2] = (ulint) rec;
270
	offsets[3] = (ulint) index;
271
#endif /* UNIV_DEBUG */
272
273
	/* read the lengths of fields 0..n */
274
	do {
275
		ulint	len;
276
277
		field = dict_index_get_nth_field(index, i);
278
		if (!(dict_field_get_col(field)->prtype
279
		      & DATA_NOT_NULL)) {
280
			/* nullable field => read the null flag */
281
282
			if (UNIV_UNLIKELY(!(byte) null_mask)) {
283
				nulls--;
284
				null_mask = 1;
285
			}
286
287
			if (*nulls & null_mask) {
288
				null_mask <<= 1;
289
				/* No length is stored for NULL fields.
290
				We do not advance offs, and we set
291
				the length to zero and enable the
292
				SQL NULL flag in offsets[]. */
293
				len = offs | REC_OFFS_SQL_NULL;
294
				goto resolved;
295
			}
296
			null_mask <<= 1;
297
		}
298
299
		if (UNIV_UNLIKELY(!field->fixed_len)) {
300
			/* Variable-length field: read the length */
301
			const dict_col_t*	col
302
				= dict_field_get_col(field);
303
			len = *lens--;
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
304
			/* If the maximum length of the field is up
305
			to 255 bytes, the actual length is always
306
			stored in one byte. If the maximum length is
307
			more than 255 bytes, the actual length is
308
			stored in one byte for 0..127.  The length
309
			will be encoded in two bytes when it is 128 or
310
			more, or when the field is stored externally. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
311
			if (UNIV_UNLIKELY(col->len > 255)
312
			    || UNIV_UNLIKELY(col->mtype
313
					     == DATA_BLOB)) {
314
				if (len & 0x80) {
315
					/* 1exxxxxxx xxxxxxxx */
316
					len <<= 8;
317
					len |= *lens--;
318
319
					offs += len & 0x3fff;
320
					if (UNIV_UNLIKELY(len
321
							  & 0x4000)) {
322
						ut_ad(dict_index_is_clust
323
						      (index));
324
						any_ext = REC_OFFS_EXTERNAL;
325
						len = offs
326
							| REC_OFFS_EXTERNAL;
327
					} else {
328
						len = offs;
329
					}
330
331
					goto resolved;
332
				}
333
			}
334
335
			len = offs += len;
336
		} else {
337
			len = offs += field->fixed_len;
338
		}
339
resolved:
340
		rec_offs_base(offsets)[i + 1] = len;
341
	} while (++i < rec_offs_n_fields(offsets));
342
343
	*rec_offs_base(offsets)
344
		= (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
345
}
346
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
347
/******************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
348
The following function determines the offsets to each field in the
349
record.	 The offsets are written to a previously allocated array of
350
ulint, where rec_offs_n_fields(offsets) has been initialized to the
351
number of fields in the record.	 The rest of the array will be
352
initialized by this function.  rec_offs_base(offsets)[0] will be set
353
to the extra size (if REC_OFFS_COMPACT is set, the record is in the
354
new format; if REC_OFFS_EXTERNAL is set, the record contains externally
355
stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to
356
offsets past the end of fields 0..n_fields, or to the beginning of
357
fields 1..n_fields+1.  When the high-order bit of the offset at [i+1]
358
is set (REC_OFFS_SQL_NULL), the field i is NULL.  When the second
359
high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
360
field i is being stored externally. */
361
static
362
void
363
rec_init_offsets(
364
/*=============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
365
	const rec_t*		rec,	/*!< in: physical record */
366
	const dict_index_t*	index,	/*!< in: record descriptor */
367
	ulint*			offsets)/*!< in/out: array of offsets;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
368
					in: n=rec_offs_n_fields(offsets) */
369
{
370
	ulint	i	= 0;
371
	ulint	offs;
372
373
	rec_offs_make_valid(rec, index, offsets);
374
375
	if (dict_table_is_comp(index->table)) {
376
		const byte*	nulls;
377
		const byte*	lens;
378
		dict_field_t*	field;
379
		ulint		null_mask;
380
		ulint		status = rec_get_status(rec);
381
		ulint		n_node_ptr_field = ULINT_UNDEFINED;
382
383
		switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
384
		case REC_STATUS_INFIMUM:
385
		case REC_STATUS_SUPREMUM:
386
			/* the field is 8 bytes long */
387
			rec_offs_base(offsets)[0]
388
				= REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
389
			rec_offs_base(offsets)[1] = 8;
390
			return;
391
		case REC_STATUS_NODE_PTR:
392
			n_node_ptr_field
393
				= dict_index_get_n_unique_in_tree(index);
394
			break;
395
		case REC_STATUS_ORDINARY:
396
			rec_init_offsets_comp_ordinary(rec,
397
						       REC_N_NEW_EXTRA_BYTES,
398
						       index, offsets);
399
			return;
400
		}
401
402
		nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
403
		lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
404
		offs = 0;
405
		null_mask = 1;
406
407
		/* read the lengths of fields 0..n */
408
		do {
409
			ulint	len;
410
			if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
411
				len = offs += 4;
412
				goto resolved;
413
			}
414
415
			field = dict_index_get_nth_field(index, i);
416
			if (!(dict_field_get_col(field)->prtype
417
			      & DATA_NOT_NULL)) {
418
				/* nullable field => read the null flag */
419
420
				if (UNIV_UNLIKELY(!(byte) null_mask)) {
421
					nulls--;
422
					null_mask = 1;
423
				}
424
425
				if (*nulls & null_mask) {
426
					null_mask <<= 1;
427
					/* No length is stored for NULL fields.
428
					We do not advance offs, and we set
429
					the length to zero and enable the
430
					SQL NULL flag in offsets[]. */
431
					len = offs | REC_OFFS_SQL_NULL;
432
					goto resolved;
433
				}
434
				null_mask <<= 1;
435
			}
436
437
			if (UNIV_UNLIKELY(!field->fixed_len)) {
438
				/* Variable-length field: read the length */
439
				const dict_col_t*	col
440
					= dict_field_get_col(field);
441
				len = *lens--;
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
442
				/* If the maximum length of the field
443
				is up to 255 bytes, the actual length
444
				is always stored in one byte. If the
445
				maximum length is more than 255 bytes,
446
				the actual length is stored in one
447
				byte for 0..127.  The length will be
448
				encoded in two bytes when it is 128 or
449
				more, or when the field is stored
450
				externally. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
451
				if (UNIV_UNLIKELY(col->len > 255)
452
				    || UNIV_UNLIKELY(col->mtype
453
						     == DATA_BLOB)) {
454
					if (len & 0x80) {
455
						/* 1exxxxxxx xxxxxxxx */
456
457
						len <<= 8;
458
						len |= *lens--;
459
460
						/* B-tree node pointers
461
						must not contain externally
462
						stored columns.  Thus
463
						the "e" flag must be 0. */
464
						ut_a(!(len & 0x4000));
465
						offs += len & 0x3fff;
466
						len = offs;
467
468
						goto resolved;
469
					}
470
				}
471
472
				len = offs += len;
473
			} else {
474
				len = offs += field->fixed_len;
475
			}
476
resolved:
477
			rec_offs_base(offsets)[i + 1] = len;
478
		} while (++i < rec_offs_n_fields(offsets));
479
480
		*rec_offs_base(offsets)
481
			= (rec - (lens + 1)) | REC_OFFS_COMPACT;
482
	} else {
483
		/* Old-style record: determine extra size and end offsets */
484
		offs = REC_N_OLD_EXTRA_BYTES;
485
		if (rec_get_1byte_offs_flag(rec)) {
486
			offs += rec_offs_n_fields(offsets);
487
			*rec_offs_base(offsets) = offs;
488
			/* Determine offsets to fields */
489
			do {
490
				offs = rec_1_get_field_end_info(rec, i);
491
				if (offs & REC_1BYTE_SQL_NULL_MASK) {
492
					offs &= ~REC_1BYTE_SQL_NULL_MASK;
493
					offs |= REC_OFFS_SQL_NULL;
494
				}
495
				rec_offs_base(offsets)[1 + i] = offs;
496
			} while (++i < rec_offs_n_fields(offsets));
497
		} else {
498
			offs += 2 * rec_offs_n_fields(offsets);
499
			*rec_offs_base(offsets) = offs;
500
			/* Determine offsets to fields */
501
			do {
502
				offs = rec_2_get_field_end_info(rec, i);
503
				if (offs & REC_2BYTE_SQL_NULL_MASK) {
504
					offs &= ~REC_2BYTE_SQL_NULL_MASK;
505
					offs |= REC_OFFS_SQL_NULL;
506
				}
507
				if (offs & REC_2BYTE_EXTERN_MASK) {
508
					offs &= ~REC_2BYTE_EXTERN_MASK;
509
					offs |= REC_OFFS_EXTERNAL;
510
					*rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
511
				}
512
				rec_offs_base(offsets)[1 + i] = offs;
513
			} while (++i < rec_offs_n_fields(offsets));
514
		}
515
	}
516
}
517
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
518
/******************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
519
The following function determines the offsets to each field
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
520
in the record.	It can reuse a previously returned array.
521
@return	the new offsets */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
522
UNIV_INTERN
523
ulint*
524
rec_get_offsets_func(
525
/*=================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
526
	const rec_t*		rec,	/*!< in: physical record */
527
	const dict_index_t*	index,	/*!< in: record descriptor */
528
	ulint*			offsets,/*!< in/out: array consisting of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
529
					offsets[0] allocated elements,
530
					or an array from rec_get_offsets(),
531
					or NULL */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
532
	ulint			n_fields,/*!< in: maximum number of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
533
					initialized fields
534
					 (ULINT_UNDEFINED if all fields) */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
535
	mem_heap_t**		heap,	/*!< in/out: memory heap */
536
	const char*		file,	/*!< in: file name where called */
537
	ulint			line)	/*!< in: line number where called */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
538
{
539
	ulint	n;
540
	ulint	size;
541
542
	ut_ad(rec);
543
	ut_ad(index);
544
	ut_ad(heap);
545
546
	if (dict_table_is_comp(index->table)) {
547
		switch (UNIV_EXPECT(rec_get_status(rec),
548
				    REC_STATUS_ORDINARY)) {
549
		case REC_STATUS_ORDINARY:
550
			n = dict_index_get_n_fields(index);
551
			break;
552
		case REC_STATUS_NODE_PTR:
553
			n = dict_index_get_n_unique_in_tree(index) + 1;
554
			break;
555
		case REC_STATUS_INFIMUM:
556
		case REC_STATUS_SUPREMUM:
557
			/* infimum or supremum record */
558
			n = 1;
559
			break;
560
		default:
561
			ut_error;
562
			return(NULL);
563
		}
564
	} else {
565
		n = rec_get_n_fields_old(rec);
566
	}
567
568
	if (UNIV_UNLIKELY(n_fields < n)) {
569
		n = n_fields;
570
	}
571
572
	size = n + (1 + REC_OFFS_HEADER_SIZE);
573
574
	if (UNIV_UNLIKELY(!offsets)
575
	    || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
576
		if (UNIV_UNLIKELY(!*heap)) {
577
			*heap = mem_heap_create_func(size * sizeof(ulint),
578
						     MEM_HEAP_DYNAMIC,
579
						     file, line);
580
		}
2023.3.12 by Monty Taylor
Through rem0rec.
581
		offsets = static_cast<unsigned long *>(mem_heap_alloc(*heap, size * sizeof(ulint)));
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
582
		rec_offs_set_n_alloc(offsets, size);
583
	}
584
585
	rec_offs_set_n_fields(offsets, n);
586
	rec_init_offsets(rec, index, offsets);
587
	return(offsets);
588
}
589
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
590
/******************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
591
The following function determines the offsets to each field
592
in the record.  It can reuse a previously allocated array. */
593
UNIV_INTERN
594
void
595
rec_get_offsets_reverse(
596
/*====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
597
	const byte*		extra,	/*!< in: the extra bytes of a
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
598
					compact record in reverse order,
599
					excluding the fixed-size
600
					REC_N_NEW_EXTRA_BYTES */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
601
	const dict_index_t*	index,	/*!< in: record descriptor */
602
	ulint			node_ptr,/*!< in: nonzero=node pointer,
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
603
					0=leaf node */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
604
	ulint*			offsets)/*!< in/out: array consisting of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
605
					offsets[0] allocated elements */
606
{
607
	ulint		n;
608
	ulint		i;
609
	ulint		offs;
610
	ulint		any_ext;
611
	const byte*	nulls;
612
	const byte*	lens;
613
	dict_field_t*	field;
614
	ulint		null_mask;
615
	ulint		n_node_ptr_field;
616
617
	ut_ad(extra);
618
	ut_ad(index);
619
	ut_ad(offsets);
620
	ut_ad(dict_table_is_comp(index->table));
621
622
	if (UNIV_UNLIKELY(node_ptr)) {
623
		n_node_ptr_field = dict_index_get_n_unique_in_tree(index);
624
		n = n_node_ptr_field + 1;
625
	} else {
626
		n_node_ptr_field = ULINT_UNDEFINED;
627
		n = dict_index_get_n_fields(index);
628
	}
629
630
	ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
631
	rec_offs_set_n_fields(offsets, n);
632
633
	nulls = extra;
634
	lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
635
	i = offs = 0;
636
	null_mask = 1;
637
	any_ext = 0;
638
639
	/* read the lengths of fields 0..n */
640
	do {
641
		ulint	len;
642
		if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
643
			len = offs += 4;
644
			goto resolved;
645
		}
646
647
		field = dict_index_get_nth_field(index, i);
648
		if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
649
			/* nullable field => read the null flag */
650
651
			if (UNIV_UNLIKELY(!(byte) null_mask)) {
652
				nulls++;
653
				null_mask = 1;
654
			}
655
656
			if (*nulls & null_mask) {
657
				null_mask <<= 1;
658
				/* No length is stored for NULL fields.
659
				We do not advance offs, and we set
660
				the length to zero and enable the
661
				SQL NULL flag in offsets[]. */
662
				len = offs | REC_OFFS_SQL_NULL;
663
				goto resolved;
664
			}
665
			null_mask <<= 1;
666
		}
667
668
		if (UNIV_UNLIKELY(!field->fixed_len)) {
669
			/* Variable-length field: read the length */
670
			const dict_col_t*	col
671
				= dict_field_get_col(field);
672
			len = *lens++;
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
673
			/* If the maximum length of the field is up
674
			to 255 bytes, the actual length is always
675
			stored in one byte. If the maximum length is
676
			more than 255 bytes, the actual length is
677
			stored in one byte for 0..127.  The length
678
			will be encoded in two bytes when it is 128 or
679
			more, or when the field is stored externally. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
680
			if (UNIV_UNLIKELY(col->len > 255)
681
			    || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
682
				if (len & 0x80) {
683
					/* 1exxxxxxx xxxxxxxx */
684
					len <<= 8;
685
					len |= *lens++;
686
687
					offs += len & 0x3fff;
688
					if (UNIV_UNLIKELY(len & 0x4000)) {
689
						any_ext = REC_OFFS_EXTERNAL;
690
						len = offs | REC_OFFS_EXTERNAL;
691
					} else {
692
						len = offs;
693
					}
694
695
					goto resolved;
696
				}
697
			}
698
699
			len = offs += len;
700
		} else {
701
			len = offs += field->fixed_len;
702
		}
703
resolved:
704
		rec_offs_base(offsets)[i + 1] = len;
705
	} while (++i < rec_offs_n_fields(offsets));
706
707
	ut_ad(lens >= extra);
708
	*rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
709
		| REC_OFFS_COMPACT | any_ext;
710
}
711
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
712
/************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
713
The following function is used to get the offset to the nth
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
714
data field in an old-style record.
715
@return	offset to the field */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
716
UNIV_INTERN
717
ulint
718
rec_get_nth_field_offs_old(
719
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
720
	const rec_t*	rec,	/*!< in: record */
721
	ulint		n,	/*!< in: index of the field */
722
	ulint*		len)	/*!< out: length of the field;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
723
				UNIV_SQL_NULL if SQL null */
724
{
725
	ulint	os;
726
	ulint	next_os;
727
1819.5.190 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6594 from MySQL InnoDB
728
	ut_ad(len);
729
	ut_a(rec);
730
	ut_a(n < rec_get_n_fields_old(rec));
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
731
732
	if (rec_get_1byte_offs_flag(rec)) {
733
		os = rec_1_get_field_start_offs(rec, n);
734
735
		next_os = rec_1_get_field_end_info(rec, n);
736
737
		if (next_os & REC_1BYTE_SQL_NULL_MASK) {
738
			*len = UNIV_SQL_NULL;
739
740
			return(os);
741
		}
742
743
		next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
744
	} else {
745
		os = rec_2_get_field_start_offs(rec, n);
746
747
		next_os = rec_2_get_field_end_info(rec, n);
748
749
		if (next_os & REC_2BYTE_SQL_NULL_MASK) {
750
			*len = UNIV_SQL_NULL;
751
752
			return(os);
753
		}
754
755
		next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
756
				      | REC_2BYTE_EXTERN_MASK);
757
	}
758
759
	*len = next_os - os;
760
761
	ut_ad(*len < UNIV_PAGE_SIZE);
762
763
	return(os);
764
}
765
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
766
/**********************************************************//**
767
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
768
@return	total size */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
769
UNIV_INTERN
770
ulint
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
771
rec_get_converted_size_comp_prefix(
772
/*===============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
773
	const dict_index_t*	index,	/*!< in: record descriptor;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
774
					dict_table_is_comp() is
775
					assumed to hold, even if
776
					it does not */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
777
	const dfield_t*		fields,	/*!< in: array of data fields */
778
	ulint			n_fields,/*!< in: number of data fields */
779
	ulint*			extra)	/*!< out: extra size */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
780
{
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
781
	ulint	extra_size;
782
	ulint	data_size;
783
	ulint	i;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
784
	ut_ad(index);
785
	ut_ad(fields);
786
	ut_ad(n_fields > 0);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
787
	ut_ad(n_fields <= dict_index_get_n_fields(index));
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
788
789
	extra_size = REC_N_NEW_EXTRA_BYTES
790
		+ UT_BITS_IN_BYTES(index->n_nullable);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
791
	data_size = 0;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
792
793
	/* read the lengths of fields 0..n */
794
	for (i = 0; i < n_fields; i++) {
795
		const dict_field_t*	field;
796
		ulint			len;
797
		const dict_col_t*	col;
798
799
		field = dict_index_get_nth_field(index, i);
800
		len = dfield_get_len(&fields[i]);
801
		col = dict_field_get_col(field);
802
803
		ut_ad(dict_col_type_assert_equal(col,
804
						 dfield_get_type(&fields[i])));
805
806
		if (dfield_is_null(&fields[i])) {
807
			/* No length is stored for NULL fields. */
808
			ut_ad(!(col->prtype & DATA_NOT_NULL));
809
			continue;
810
		}
811
812
		ut_ad(len <= col->len || col->mtype == DATA_BLOB);
813
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
814
		/* If the maximum length of a variable-length field
815
		is up to 255 bytes, the actual length is always stored
816
		in one byte. If the maximum length is more than 255
817
		bytes, the actual length is stored in one byte for
818
		0..127.  The length will be encoded in two bytes when
819
		it is 128 or more, or when the field is stored externally. */
820
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
821
		if (field->fixed_len) {
822
			ut_ad(len == field->fixed_len);
823
			/* dict_index_add_col() should guarantee this */
824
			ut_ad(!field->prefix_len
825
			      || field->fixed_len == field->prefix_len);
826
		} else if (dfield_is_ext(&fields[i])) {
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
827
			ut_ad(col->len >= 256 || col->mtype == DATA_BLOB);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
828
			extra_size += 2;
829
		} else if (len < 128
830
			   || (col->len < 256 && col->mtype != DATA_BLOB)) {
831
			extra_size++;
832
		} else {
833
			/* For variable-length columns, we look up the
834
			maximum length from the column itself.  If this
835
			is a prefix index column shorter than 256 bytes,
836
			this will waste one byte. */
837
			extra_size += 2;
838
		}
839
		data_size += len;
840
	}
841
842
	if (UNIV_LIKELY_NULL(extra)) {
843
		*extra = extra_size;
844
	}
845
846
	return(extra_size + data_size);
847
}
848
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
849
/**********************************************************//**
850
Determines the size of a data tuple in ROW_FORMAT=COMPACT.
851
@return	total size */
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
852
UNIV_INTERN
853
ulint
854
rec_get_converted_size_comp(
855
/*========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
856
	const dict_index_t*	index,	/*!< in: record descriptor;
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
857
					dict_table_is_comp() is
858
					assumed to hold, even if
859
					it does not */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
860
	ulint			status,	/*!< in: status bits of the record */
861
	const dfield_t*		fields,	/*!< in: array of data fields */
862
	ulint			n_fields,/*!< in: number of data fields */
863
	ulint*			extra)	/*!< out: extra size */
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
864
{
865
	ulint	size;
866
	ut_ad(index);
867
	ut_ad(fields);
868
	ut_ad(n_fields > 0);
869
870
	switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
871
	case REC_STATUS_ORDINARY:
872
		ut_ad(n_fields == dict_index_get_n_fields(index));
873
		size = 0;
874
		break;
875
	case REC_STATUS_NODE_PTR:
876
		n_fields--;
877
		ut_ad(n_fields == dict_index_get_n_unique_in_tree(index));
878
		ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
879
		size = REC_NODE_PTR_SIZE; /* child page number */
880
		break;
881
	case REC_STATUS_INFIMUM:
882
	case REC_STATUS_SUPREMUM:
883
		/* infimum or supremum record, 8 data bytes */
884
		if (UNIV_LIKELY_NULL(extra)) {
885
			*extra = REC_N_NEW_EXTRA_BYTES;
886
		}
887
		return(REC_N_NEW_EXTRA_BYTES + 8);
888
	default:
889
		ut_error;
890
		return(ULINT_UNDEFINED);
891
	}
892
893
	return(size + rec_get_converted_size_comp_prefix(index, fields,
894
							 n_fields, extra));
895
}
896
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
897
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
898
Sets the value of the ith field SQL null bit of an old-style record. */
899
UNIV_INTERN
900
void
901
rec_set_nth_field_null_bit(
902
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
903
	rec_t*	rec,	/*!< in: record */
904
	ulint	i,	/*!< in: ith field */
905
	ibool	val)	/*!< in: value to set */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
906
{
907
	ulint	info;
908
909
	if (rec_get_1byte_offs_flag(rec)) {
910
911
		info = rec_1_get_field_end_info(rec, i);
912
913
		if (val) {
914
			info = info | REC_1BYTE_SQL_NULL_MASK;
915
		} else {
916
			info = info & ~REC_1BYTE_SQL_NULL_MASK;
917
		}
918
919
		rec_1_set_field_end_info(rec, i, info);
920
921
		return;
922
	}
923
924
	info = rec_2_get_field_end_info(rec, i);
925
926
	if (val) {
927
		info = info | REC_2BYTE_SQL_NULL_MASK;
928
	} else {
929
		info = info & ~REC_2BYTE_SQL_NULL_MASK;
930
	}
931
932
	rec_2_set_field_end_info(rec, i, info);
933
}
934
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
935
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
936
Sets an old-style record field to SQL null.
937
The physical size of the field is not changed. */
938
UNIV_INTERN
939
void
940
rec_set_nth_field_sql_null(
941
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
942
	rec_t*	rec,	/*!< in: record */
943
	ulint	n)	/*!< in: index of the field */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
944
{
945
	ulint	offset;
946
947
	offset = rec_get_field_start_offs(rec, n);
948
949
	data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
950
951
	rec_set_nth_field_null_bit(rec, n, TRUE);
952
}
953
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
954
/*********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
955
Builds an old-style physical record out of a data tuple and
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
956
stores it beginning from the start of the given buffer.
957
@return	pointer to the origin of physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
958
static
959
rec_t*
960
rec_convert_dtuple_to_rec_old(
961
/*==========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
962
	byte*		buf,	/*!< in: start address of the physical record */
963
	const dtuple_t*	dtuple,	/*!< in: data tuple */
964
	ulint		n_ext)	/*!< in: number of externally stored columns */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
965
{
966
	const dfield_t*	field;
967
	ulint		n_fields;
968
	ulint		data_size;
969
	rec_t*		rec;
970
	ulint		end_offset;
971
	ulint		ored_offset;
972
	ulint		len;
973
	ulint		i;
974
975
	ut_ad(buf && dtuple);
976
	ut_ad(dtuple_validate(dtuple));
977
	ut_ad(dtuple_check_typed(dtuple));
978
979
	n_fields = dtuple_get_n_fields(dtuple);
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
980
	data_size = dtuple_get_data_size(dtuple, 0);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
981
982
	ut_ad(n_fields > 0);
983
984
	/* Calculate the offset of the origin in the physical record */
985
986
	rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
987
#ifdef UNIV_DEBUG
988
	/* Suppress Valgrind warnings of ut_ad()
989
	in mach_write_to_1(), mach_write_to_2() et al. */
990
	memset(buf, 0xff, rec - buf + data_size);
991
#endif /* UNIV_DEBUG */
992
	/* Store the number of fields */
993
	rec_set_n_fields_old(rec, n_fields);
994
995
	/* Set the info bits of the record */
996
	rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
997
			      & REC_INFO_BITS_MASK);
998
999
	/* Store the data and the offsets */
1000
1001
	end_offset = 0;
1002
1003
	if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
1004
1005
		rec_set_1byte_offs_flag(rec, TRUE);
1006
1007
		for (i = 0; i < n_fields; i++) {
1008
1009
			field = dtuple_get_nth_field(dtuple, i);
1010
1011
			if (dfield_is_null(field)) {
1012
				len = dtype_get_sql_null_size(
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1013
					dfield_get_type(field), 0);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1014
				data_write_sql_null(rec + end_offset, len);
1015
1016
				end_offset += len;
1017
				ored_offset = end_offset
1018
					| REC_1BYTE_SQL_NULL_MASK;
1019
			} else {
1020
				/* If the data is not SQL null, store it */
1021
				len = dfield_get_len(field);
1022
1023
				memcpy(rec + end_offset,
1024
				       dfield_get_data(field), len);
1025
1026
				end_offset += len;
1027
				ored_offset = end_offset;
1028
			}
1029
1030
			rec_1_set_field_end_info(rec, i, ored_offset);
1031
		}
1032
	} else {
1033
		rec_set_1byte_offs_flag(rec, FALSE);
1034
1035
		for (i = 0; i < n_fields; i++) {
1036
1037
			field = dtuple_get_nth_field(dtuple, i);
1038
1039
			if (dfield_is_null(field)) {
1040
				len = dtype_get_sql_null_size(
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1041
					dfield_get_type(field), 0);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1042
				data_write_sql_null(rec + end_offset, len);
1043
1044
				end_offset += len;
1045
				ored_offset = end_offset
1046
					| REC_2BYTE_SQL_NULL_MASK;
1047
			} else {
1048
				/* If the data is not SQL null, store it */
1049
				len = dfield_get_len(field);
1050
1051
				memcpy(rec + end_offset,
1052
				       dfield_get_data(field), len);
1053
1054
				end_offset += len;
1055
				ored_offset = end_offset;
1056
1057
				if (dfield_is_ext(field)) {
1058
					ored_offset |= REC_2BYTE_EXTERN_MASK;
1059
				}
1060
			}
1061
1062
			rec_2_set_field_end_info(rec, i, ored_offset);
1063
		}
1064
	}
1065
1066
	return(rec);
1067
}
1068
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1069
/*********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1070
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
1071
UNIV_INTERN
1072
void
1073
rec_convert_dtuple_to_rec_comp(
1074
/*===========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1075
	rec_t*			rec,	/*!< in: origin of record */
1076
	ulint			extra,	/*!< in: number of bytes to
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1077
					reserve between the record
1078
					header and the data payload
1079
					(normally REC_N_NEW_EXTRA_BYTES) */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1080
	const dict_index_t*	index,	/*!< in: record descriptor */
1081
	ulint			status,	/*!< in: status bits of the record */
1082
	const dfield_t*		fields,	/*!< in: array of data fields */
1083
	ulint			n_fields)/*!< in: number of data fields */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1084
{
1085
	const dfield_t*	field;
1086
	const dtype_t*	type;
1087
	byte*		end;
1088
	byte*		nulls;
1089
	byte*		lens;
1090
	ulint		len;
1091
	ulint		i;
1092
	ulint		n_node_ptr_field;
1093
	ulint		fixed_len;
1094
	ulint		null_mask	= 1;
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
1095
	ut_ad(extra == 0 || dict_table_is_comp(index->table));
1096
	ut_ad(extra == 0 || extra == REC_N_NEW_EXTRA_BYTES);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1097
	ut_ad(n_fields > 0);
1098
1099
	switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1100
	case REC_STATUS_ORDINARY:
1101
		ut_ad(n_fields <= dict_index_get_n_fields(index));
1102
		n_node_ptr_field = ULINT_UNDEFINED;
1103
		break;
1104
	case REC_STATUS_NODE_PTR:
1105
		ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
1106
		n_node_ptr_field = n_fields - 1;
1107
		break;
1108
	case REC_STATUS_INFIMUM:
1109
	case REC_STATUS_SUPREMUM:
1110
		ut_ad(n_fields == 1);
1111
		n_node_ptr_field = ULINT_UNDEFINED;
1112
		break;
1113
	default:
1114
		ut_error;
1115
		return;
1116
	}
1117
1118
	end = rec;
1119
	nulls = rec - (extra + 1);
1120
	lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1121
	/* clear the SQL-null flags */
1122
	memset(lens + 1, 0, nulls - lens);
1123
1124
	/* Store the data and the offsets */
1125
1126
	for (i = 0, field = fields; i < n_fields; i++, field++) {
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
1127
		const dict_field_t*	ifield;
1128
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1129
		type = dfield_get_type(field);
1130
		len = dfield_get_len(field);
1131
1132
		if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
1133
			ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
1134
			ut_ad(len == 4);
1135
			memcpy(end, dfield_get_data(field), len);
1136
			end += 4;
1137
			break;
1138
		}
1139
1140
		if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
1141
			/* nullable field */
1142
			ut_ad(index->n_nullable > 0);
1143
1144
			if (UNIV_UNLIKELY(!(byte) null_mask)) {
1145
				nulls--;
1146
				null_mask = 1;
1147
			}
1148
1149
			ut_ad(*nulls < null_mask);
1150
1151
			/* set the null flag if necessary */
1152
			if (dfield_is_null(field)) {
1153
				*nulls |= null_mask;
1154
				null_mask <<= 1;
1155
				continue;
1156
			}
1157
1158
			null_mask <<= 1;
1159
		}
1160
		/* only nullable fields can be null */
1161
		ut_ad(!dfield_is_null(field));
1162
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
1163
		ifield = dict_index_get_nth_field(index, i);
1164
		fixed_len = ifield->fixed_len;
1165
		/* If the maximum length of a variable-length field
1166
		is up to 255 bytes, the actual length is always stored
1167
		in one byte. If the maximum length is more than 255
1168
		bytes, the actual length is stored in one byte for
1169
		0..127.  The length will be encoded in two bytes when
1170
		it is 128 or more, or when the field is stored externally. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1171
		if (fixed_len) {
1172
			ut_ad(len == fixed_len);
1173
			ut_ad(!dfield_is_ext(field));
1174
		} else if (dfield_is_ext(field)) {
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
1175
			ut_ad(ifield->col->len >= 256
1176
			      || ifield->col->mtype == DATA_BLOB);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1177
			ut_ad(len <= REC_MAX_INDEX_COL_LEN
1178
			      + BTR_EXTERN_FIELD_REF_SIZE);
1179
			*lens-- = (byte) (len >> 8) | 0xc0;
1180
			*lens-- = (byte) len;
1181
		} else {
1182
			ut_ad(len <= dtype_get_len(type)
1183
			      || dtype_get_mtype(type) == DATA_BLOB);
1184
			if (len < 128
1185
			    || (dtype_get_len(type) < 256
1186
				&& dtype_get_mtype(type) != DATA_BLOB)) {
1187
1188
				*lens-- = (byte) len;
1189
			} else {
1190
				ut_ad(len < 16384);
1191
				*lens-- = (byte) (len >> 8) | 0x80;
1192
				*lens-- = (byte) len;
1193
			}
1194
		}
1195
1196
		memcpy(end, dfield_get_data(field), len);
1197
		end += len;
1198
	}
1199
}
1200
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1201
/*********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1202
Builds a new-style physical record out of a data tuple and
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1203
stores it beginning from the start of the given buffer.
1204
@return	pointer to the origin of physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1205
static
1206
rec_t*
1207
rec_convert_dtuple_to_rec_new(
1208
/*==========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1209
	byte*			buf,	/*!< in: start address of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1210
					the physical record */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1211
	const dict_index_t*	index,	/*!< in: record descriptor */
1212
	const dtuple_t*		dtuple)	/*!< in: data tuple */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1213
{
1214
	ulint	extra_size;
1215
	ulint	status;
1216
	rec_t*	rec;
1217
1218
	status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK;
1219
	rec_get_converted_size_comp(index, status,
1220
				    dtuple->fields, dtuple->n_fields,
1221
				    &extra_size);
1222
	rec = buf + extra_size;
1223
1224
	rec_convert_dtuple_to_rec_comp(
1225
		rec, REC_N_NEW_EXTRA_BYTES, index, status,
1226
		dtuple->fields, dtuple->n_fields);
1227
1228
	/* Set the info bits of the record */
1229
	rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
1230
1231
	return(rec);
1232
}
1233
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1234
/*********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1235
Builds a physical record out of a data tuple and
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1236
stores it beginning from the start of the given buffer.
1237
@return	pointer to the origin of physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1238
UNIV_INTERN
1239
rec_t*
1240
rec_convert_dtuple_to_rec(
1241
/*======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1242
	byte*			buf,	/*!< in: start address of the
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1243
					physical record */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1244
	const dict_index_t*	index,	/*!< in: record descriptor */
1245
	const dtuple_t*		dtuple,	/*!< in: data tuple */
1246
	ulint			n_ext)	/*!< in: number of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1247
					externally stored columns */
1248
{
1249
	rec_t*	rec;
1250
1251
	ut_ad(buf && index && dtuple);
1252
	ut_ad(dtuple_validate(dtuple));
1253
	ut_ad(dtuple_check_typed(dtuple));
1254
1255
	if (dict_table_is_comp(index->table)) {
1256
		rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
1257
	} else {
1258
		rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
1259
	}
1260
1261
#ifdef UNIV_DEBUG
1262
	{
1263
		mem_heap_t*	heap	= NULL;
1264
		ulint		offsets_[REC_OFFS_NORMAL_SIZE];
1265
		const ulint*	offsets;
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
1266
		ulint		i;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1267
		rec_offs_init(offsets_);
1268
1269
		offsets = rec_get_offsets(rec, index,
1270
					  offsets_, ULINT_UNDEFINED, &heap);
1271
		ut_ad(rec_validate(rec, offsets));
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
1272
		ut_ad(dtuple_get_n_fields(dtuple)
1273
		      == rec_offs_n_fields(offsets));
1274
1275
		for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1276
			ut_ad(!dfield_is_ext(dtuple_get_nth_field(dtuple, i))
1277
			      == !rec_offs_nth_extern(offsets, i));
1278
		}
1279
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1280
		if (UNIV_LIKELY_NULL(heap)) {
1281
			mem_heap_free(heap);
1282
		}
1283
	}
1284
#endif /* UNIV_DEBUG */
1285
	return(rec);
1286
}
1287
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1288
/**************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1289
Copies the first n fields of a physical record to a data tuple. The fields
1290
are copied to the memory heap. */
1291
UNIV_INTERN
1292
void
1293
rec_copy_prefix_to_dtuple(
1294
/*======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1295
	dtuple_t*		tuple,		/*!< out: data tuple */
1296
	const rec_t*		rec,		/*!< in: physical record */
1297
	const dict_index_t*	index,		/*!< in: record descriptor */
1298
	ulint			n_fields,	/*!< in: number of fields
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1299
						to copy */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1300
	mem_heap_t*		heap)		/*!< in: memory heap */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1301
{
1302
	ulint	i;
1303
	ulint	offsets_[REC_OFFS_NORMAL_SIZE];
1304
	ulint*	offsets	= offsets_;
1305
	rec_offs_init(offsets_);
1306
1307
	offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
1308
1309
	ut_ad(rec_validate(rec, offsets));
1310
	ut_ad(dtuple_check_typed(tuple));
1311
1312
	dtuple_set_info_bits(tuple, rec_get_info_bits(
1313
				     rec, dict_table_is_comp(index->table)));
1314
1315
	for (i = 0; i < n_fields; i++) {
1316
		dfield_t*	field;
1317
		const byte*	data;
1318
		ulint		len;
1319
1320
		field = dtuple_get_nth_field(tuple, i);
1321
		data = rec_get_nth_field(rec, offsets, i, &len);
1322
1323
		if (len != UNIV_SQL_NULL) {
1324
			dfield_set_data(field,
1325
					mem_heap_dup(heap, data, len), len);
1326
			ut_ad(!rec_offs_nth_extern(offsets, i));
1327
		} else {
1328
			dfield_set_null(field);
1329
		}
1330
	}
1331
}
1332
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1333
/**************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1334
Copies the first n fields of an old-style physical record
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1335
to a new physical record in a buffer.
1336
@return	own: copied record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1337
static
1338
rec_t*
1339
rec_copy_prefix_to_buf_old(
1340
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1341
	const rec_t*	rec,		/*!< in: physical record */
1342
	ulint		n_fields,	/*!< in: number of fields to copy */
1343
	ulint		area_end,	/*!< in: end of the prefix data */
1344
	byte**		buf,		/*!< in/out: memory buffer for
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1345
					the copied prefix, or NULL */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1346
	ulint*		buf_size)	/*!< in/out: buffer size */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1347
{
1348
	rec_t*	copy_rec;
1349
	ulint	area_start;
1350
	ulint	prefix_len;
1351
1352
	if (rec_get_1byte_offs_flag(rec)) {
1353
		area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
1354
	} else {
1355
		area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
1356
	}
1357
1358
	prefix_len = area_start + area_end;
1359
1360
	if ((*buf == NULL) || (*buf_size < prefix_len)) {
1361
		if (*buf != NULL) {
1362
			mem_free(*buf);
1363
		}
1364
2023.3.12 by Monty Taylor
Through rem0rec.
1365
		*buf = static_cast<byte *>(mem_alloc2(prefix_len, buf_size));
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1366
	}
1367
1368
	ut_memcpy(*buf, rec - area_start, prefix_len);
1369
1370
	copy_rec = *buf + area_start;
1371
1372
	rec_set_n_fields_old(copy_rec, n_fields);
1373
1374
	return(copy_rec);
1375
}
1376
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1377
/**************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1378
Copies the first n fields of a physical record to a new physical record in
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1379
a buffer.
1380
@return	own: copied record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1381
UNIV_INTERN
1382
rec_t*
1383
rec_copy_prefix_to_buf(
1384
/*===================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1385
	const rec_t*		rec,		/*!< in: physical record */
1386
	const dict_index_t*	index,		/*!< in: record descriptor */
1387
	ulint			n_fields,	/*!< in: number of fields
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1388
						to copy */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1389
	byte**			buf,		/*!< in/out: memory buffer
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1390
						for the copied prefix,
1391
						or NULL */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1392
	ulint*			buf_size)	/*!< in/out: buffer size */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1393
{
1394
	const byte*	nulls;
1395
	const byte*	lens;
1396
	ulint		i;
1397
	ulint		prefix_len;
1398
	ulint		null_mask;
1399
	ulint		status;
1400
1401
	UNIV_PREFETCH_RW(*buf);
1402
1403
	if (!dict_table_is_comp(index->table)) {
1404
		ut_ad(rec_validate_old(rec));
1405
		return(rec_copy_prefix_to_buf_old(
1406
			       rec, n_fields,
1407
			       rec_get_field_start_offs(rec, n_fields),
1408
			       buf, buf_size));
1409
	}
1410
1411
	status = rec_get_status(rec);
1412
1413
	switch (status) {
1414
	case REC_STATUS_ORDINARY:
1415
		ut_ad(n_fields <= dict_index_get_n_fields(index));
1416
		break;
1417
	case REC_STATUS_NODE_PTR:
1418
		/* it doesn't make sense to copy the child page number field */
1419
		ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
1420
		break;
1421
	case REC_STATUS_INFIMUM:
1422
	case REC_STATUS_SUPREMUM:
1423
		/* infimum or supremum record: no sense to copy anything */
1424
	default:
1425
		ut_error;
1426
		return(NULL);
1427
	}
1428
1429
	nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1430
	lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1431
	UNIV_PREFETCH_R(lens);
1432
	prefix_len = 0;
1433
	null_mask = 1;
1434
1435
	/* read the lengths of fields 0..n */
1436
	for (i = 0; i < n_fields; i++) {
1437
		const dict_field_t*	field;
1438
		const dict_col_t*	col;
1439
1440
		field = dict_index_get_nth_field(index, i);
1441
		col = dict_field_get_col(field);
1442
1443
		if (!(col->prtype & DATA_NOT_NULL)) {
1444
			/* nullable field => read the null flag */
1445
			if (UNIV_UNLIKELY(!(byte) null_mask)) {
1446
				nulls--;
1447
				null_mask = 1;
1448
			}
1449
1450
			if (*nulls & null_mask) {
1451
				null_mask <<= 1;
1452
				continue;
1453
			}
1454
1455
			null_mask <<= 1;
1456
		}
1457
1458
		if (field->fixed_len) {
1459
			prefix_len += field->fixed_len;
1460
		} else {
1461
			ulint	len = *lens--;
1819.7.69 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100422112442-enb8mpw7jla5uvaz from MySQL InnoDB
1462
			/* If the maximum length of the column is up
1463
			to 255 bytes, the actual length is always
1464
			stored in one byte. If the maximum length is
1465
			more than 255 bytes, the actual length is
1466
			stored in one byte for 0..127.  The length
1467
			will be encoded in two bytes when it is 128 or
1468
			more, or when the column is stored externally. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1469
			if (col->len > 255 || col->mtype == DATA_BLOB) {
1470
				if (len & 0x80) {
1471
					/* 1exxxxxx */
1472
					len &= 0x3f;
1473
					len <<= 8;
1474
					len |= *lens--;
1475
					UNIV_PREFETCH_R(lens);
1476
				}
1477
			}
1478
			prefix_len += len;
1479
		}
1480
	}
1481
1482
	UNIV_PREFETCH_R(rec + prefix_len);
1483
1484
	prefix_len += rec - (lens + 1);
1485
1486
	if ((*buf == NULL) || (*buf_size < prefix_len)) {
1487
		if (*buf != NULL) {
1488
			mem_free(*buf);
1489
		}
1490
2023.3.12 by Monty Taylor
Through rem0rec.
1491
		*buf = static_cast<byte *>(mem_alloc2(prefix_len, buf_size));
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1492
	}
1493
1494
	memcpy(*buf, lens + 1, prefix_len);
1495
1496
	return(*buf + (rec - (lens + 1)));
1497
}
1498
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1499
/***************************************************************//**
1500
Validates the consistency of an old-style physical record.
1501
@return	TRUE if ok */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1502
static
1503
ibool
1504
rec_validate_old(
1505
/*=============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1506
	const rec_t*	rec)	/*!< in: physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1507
{
1508
	const byte*	data;
1509
	ulint		len;
1510
	ulint		n_fields;
1511
	ulint		len_sum		= 0;
1512
	ulint		sum		= 0;
1513
	ulint		i;
1514
1515
	ut_a(rec);
1516
	n_fields = rec_get_n_fields_old(rec);
1517
1518
	if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1519
		fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1520
			(ulong) n_fields);
1521
		return(FALSE);
1522
	}
1523
1524
	for (i = 0; i < n_fields; i++) {
1525
		data = rec_get_nth_field_old(rec, i, &len);
1526
1527
		if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1528
			fprintf(stderr,
1529
				"InnoDB: Error: record field %lu len %lu\n",
1530
				(ulong) i,
1531
				(ulong) len);
1532
			return(FALSE);
1533
		}
1534
1535
		if (len != UNIV_SQL_NULL) {
1536
			len_sum += len;
1537
			sum += *(data + len -1); /* dereference the
1538
						 end of the field to
1539
						 cause a memory trap
1540
						 if possible */
1541
		} else {
1542
			len_sum += rec_get_nth_field_size(rec, i);
1543
		}
1544
	}
1545
1546
	if (len_sum != rec_get_data_size_old(rec)) {
1547
		fprintf(stderr,
1548
			"InnoDB: Error: record len should be %lu, len %lu\n",
1549
			(ulong) len_sum,
1550
			rec_get_data_size_old(rec));
1551
		return(FALSE);
1552
	}
1553
1554
	rec_dummy = sum; /* This is here only to fool the compiler */
1555
1556
	return(TRUE);
1557
}
1558
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1559
/***************************************************************//**
1560
Validates the consistency of a physical record.
1561
@return	TRUE if ok */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1562
UNIV_INTERN
1563
ibool
1564
rec_validate(
1565
/*=========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1566
	const rec_t*	rec,	/*!< in: physical record */
1567
	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1568
{
1569
	const byte*	data;
1570
	ulint		len;
1571
	ulint		n_fields;
1572
	ulint		len_sum		= 0;
1573
	ulint		sum		= 0;
1574
	ulint		i;
1575
1576
	ut_a(rec);
1577
	n_fields = rec_offs_n_fields(offsets);
1578
1579
	if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1580
		fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1581
			(ulong) n_fields);
1582
		return(FALSE);
1583
	}
1584
1585
	ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
1586
1587
	for (i = 0; i < n_fields; i++) {
1588
		data = rec_get_nth_field(rec, offsets, i, &len);
1589
1590
		if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1591
			fprintf(stderr,
1592
				"InnoDB: Error: record field %lu len %lu\n",
1593
				(ulong) i,
1594
				(ulong) len);
1595
			return(FALSE);
1596
		}
1597
1598
		if (len != UNIV_SQL_NULL) {
1599
			len_sum += len;
1600
			sum += *(data + len -1); /* dereference the
1601
						 end of the field to
1602
						 cause a memory trap
1603
						 if possible */
1604
		} else if (!rec_offs_comp(offsets)) {
1605
			len_sum += rec_get_nth_field_size(rec, i);
1606
		}
1607
	}
1608
1609
	if (len_sum != rec_offs_data_size(offsets)) {
1610
		fprintf(stderr,
1611
			"InnoDB: Error: record len should be %lu, len %lu\n",
1612
			(ulong) len_sum,
1613
			(ulong) rec_offs_data_size(offsets));
1614
		return(FALSE);
1615
	}
1616
1617
	rec_dummy = sum; /* This is here only to fool the compiler */
1618
1619
	if (!rec_offs_comp(offsets)) {
1620
		ut_a(rec_validate_old(rec));
1621
	}
1622
1623
	return(TRUE);
1624
}
1625
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1626
/***************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1627
Prints an old-style physical record. */
1628
UNIV_INTERN
1629
void
1630
rec_print_old(
1631
/*==========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1632
	FILE*		file,	/*!< in: file where to print */
1633
	const rec_t*	rec)	/*!< in: physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1634
{
1635
	const byte*	data;
1636
	ulint		len;
1637
	ulint		n;
1638
	ulint		i;
1639
1640
	ut_ad(rec);
1641
1642
	n = rec_get_n_fields_old(rec);
1643
1644
	fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1645
		" %u-byte offsets; info bits %lu\n",
1646
		(ulong) n,
1647
		rec_get_1byte_offs_flag(rec) ? 1 : 2,
1648
		(ulong) rec_get_info_bits(rec, FALSE));
1649
1650
	for (i = 0; i < n; i++) {
1651
1652
		data = rec_get_nth_field_old(rec, i, &len);
1653
1654
		fprintf(file, " %lu:", (ulong) i);
1655
1656
		if (len != UNIV_SQL_NULL) {
1657
			if (len <= 30) {
1658
1659
				ut_print_buf(file, data, len);
1660
			} else {
1661
				ut_print_buf(file, data, 30);
1662
1663
				fprintf(file, " (total %lu bytes)",
1664
					(ulong) len);
1665
			}
1666
		} else {
1667
			fprintf(file, " SQL NULL, size %lu ",
1668
				rec_get_nth_field_size(rec, i));
1669
		}
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1670
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1671
		putc(';', file);
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1672
		putc('\n', file);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1673
	}
1674
1675
	rec_validate_old(rec);
1676
}
1677
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1678
#ifndef UNIV_HOTBACKUP
1679
/***************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1680
Prints a physical record in ROW_FORMAT=COMPACT.  Ignores the
1681
record header. */
1682
UNIV_INTERN
1683
void
1684
rec_print_comp(
1685
/*===========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1686
	FILE*		file,	/*!< in: file where to print */
1687
	const rec_t*	rec,	/*!< in: physical record */
1688
	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1689
{
1690
	ulint	i;
1691
1692
	for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1693
		const byte*	data;
1694
		ulint		len;
1695
1696
		data = rec_get_nth_field(rec, offsets, i, &len);
1697
1698
		fprintf(file, " %lu:", (ulong) i);
1699
1700
		if (len != UNIV_SQL_NULL) {
1701
			if (len <= 30) {
1702
1703
				ut_print_buf(file, data, len);
1704
			} else {
1705
				ut_print_buf(file, data, 30);
1706
1707
				fprintf(file, " (total %lu bytes)",
1708
					(ulong) len);
1709
			}
1710
		} else {
1711
			fputs(" SQL NULL", file);
1712
		}
1713
		putc(';', file);
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1714
		putc('\n', file);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1715
	}
1716
}
1717
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1718
/***************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1719
Prints a physical record. */
1720
UNIV_INTERN
1721
void
1722
rec_print_new(
1723
/*==========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1724
	FILE*		file,	/*!< in: file where to print */
1725
	const rec_t*	rec,	/*!< in: physical record */
1726
	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1727
{
1728
	ut_ad(rec);
1729
	ut_ad(offsets);
1730
	ut_ad(rec_offs_validate(rec, NULL, offsets));
1731
1732
	if (!rec_offs_comp(offsets)) {
1733
		rec_print_old(file, rec);
1734
		return;
1735
	}
1736
1737
	fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1738
		" compact format; info bits %lu\n",
1739
		(ulong) rec_offs_n_fields(offsets),
1740
		(ulong) rec_get_info_bits(rec, TRUE));
1741
1742
	rec_print_comp(file, rec, offsets);
1743
	rec_validate(rec, offsets);
1744
}
1745
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1746
/***************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1747
Prints a physical record. */
1748
UNIV_INTERN
1749
void
1750
rec_print(
1751
/*======*/
1819.9.169 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20101019060415-bj3u6ewk022mk4nr from MySQL InnoDB
1752
	FILE*			file,	/*!< in: file where to print */
1753
	const rec_t*		rec,	/*!< in: physical record */
1754
	const dict_index_t*	index)	/*!< in: record descriptor */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1755
{
1756
	ut_ad(index);
1757
1758
	if (!dict_table_is_comp(index->table)) {
1759
		rec_print_old(file, rec);
1760
		return;
1761
	} else {
1762
		mem_heap_t*	heap	= NULL;
1763
		ulint		offsets_[REC_OFFS_NORMAL_SIZE];
1764
		rec_offs_init(offsets_);
1765
1766
		rec_print_new(file, rec,
1767
			      rec_get_offsets(rec, index, offsets_,
1768
					      ULINT_UNDEFINED, &heap));
1769
		if (UNIV_LIKELY_NULL(heap)) {
1770
			mem_heap_free(heap);
1771
		}
1772
	}
1773
}
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1774
#endif /* !UNIV_HOTBACKUP */