~drizzle-trunk/drizzle/development

641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1
/*****************************************************************************
2
3
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
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--;
215
			if (UNIV_UNLIKELY(col->len > 255)
216
			    || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
217
				if (len & 0x80) {
218
					/* 1exxxxxxx xxxxxxxx */
219
					if (len & 0x40) {
220
						n_extern++;
221
					}
222
					lens--;
223
				}
224
			}
225
		}
226
	} while (++i < n);
227
228
	return(n_extern);
229
}
230
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
231
/******************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
232
Determine the offset to each field in a leaf-page record
233
in ROW_FORMAT=COMPACT.  This is a special case of
234
rec_init_offsets() and rec_get_offsets_func(). */
235
UNIV_INTERN
236
void
237
rec_init_offsets_comp_ordinary(
238
/*===========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
239
	const rec_t*		rec,	/*!< in: physical record in
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
240
					ROW_FORMAT=COMPACT */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
241
	ulint			extra,	/*!< in: number of bytes to reserve
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
242
					between the record header and
243
					the data payload
244
					(usually REC_N_NEW_EXTRA_BYTES) */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
245
	const dict_index_t*	index,	/*!< in: record descriptor */
246
	ulint*			offsets)/*!< in/out: array of offsets;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
247
					in: n=rec_offs_n_fields(offsets) */
248
{
249
	ulint		i		= 0;
250
	ulint		offs		= 0;
251
	ulint		any_ext		= 0;
252
	const byte*	nulls		= rec - (extra + 1);
253
	const byte*	lens		= nulls
254
		- UT_BITS_IN_BYTES(index->n_nullable);
255
	dict_field_t*	field;
256
	ulint		null_mask	= 1;
257
258
#ifdef UNIV_DEBUG
259
	/* We cannot invoke rec_offs_make_valid() here, because it can hold
260
	that extra != REC_N_NEW_EXTRA_BYTES.  Similarly, rec_offs_validate()
261
	will fail in that case, because it invokes rec_get_status(). */
262
	offsets[2] = (ulint) rec;
263
	offsets[3] = (ulint) index;
264
#endif /* UNIV_DEBUG */
265
266
	/* read the lengths of fields 0..n */
267
	do {
268
		ulint	len;
269
270
		field = dict_index_get_nth_field(index, i);
271
		if (!(dict_field_get_col(field)->prtype
272
		      & DATA_NOT_NULL)) {
273
			/* nullable field => read the null flag */
274
275
			if (UNIV_UNLIKELY(!(byte) null_mask)) {
276
				nulls--;
277
				null_mask = 1;
278
			}
279
280
			if (*nulls & null_mask) {
281
				null_mask <<= 1;
282
				/* No length is stored for NULL fields.
283
				We do not advance offs, and we set
284
				the length to zero and enable the
285
				SQL NULL flag in offsets[]. */
286
				len = offs | REC_OFFS_SQL_NULL;
287
				goto resolved;
288
			}
289
			null_mask <<= 1;
290
		}
291
292
		if (UNIV_UNLIKELY(!field->fixed_len)) {
293
			/* Variable-length field: read the length */
294
			const dict_col_t*	col
295
				= dict_field_get_col(field);
296
			len = *lens--;
297
			if (UNIV_UNLIKELY(col->len > 255)
298
			    || UNIV_UNLIKELY(col->mtype
299
					     == DATA_BLOB)) {
300
				if (len & 0x80) {
301
					/* 1exxxxxxx xxxxxxxx */
302
					len <<= 8;
303
					len |= *lens--;
304
305
					offs += len & 0x3fff;
306
					if (UNIV_UNLIKELY(len
307
							  & 0x4000)) {
308
						ut_ad(dict_index_is_clust
309
						      (index));
310
						any_ext = REC_OFFS_EXTERNAL;
311
						len = offs
312
							| REC_OFFS_EXTERNAL;
313
					} else {
314
						len = offs;
315
					}
316
317
					goto resolved;
318
				}
319
			}
320
321
			len = offs += len;
322
		} else {
323
			len = offs += field->fixed_len;
324
		}
325
resolved:
326
		rec_offs_base(offsets)[i + 1] = len;
327
	} while (++i < rec_offs_n_fields(offsets));
328
329
	*rec_offs_base(offsets)
330
		= (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
331
}
332
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
333
/******************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
334
The following function determines the offsets to each field in the
335
record.	 The offsets are written to a previously allocated array of
336
ulint, where rec_offs_n_fields(offsets) has been initialized to the
337
number of fields in the record.	 The rest of the array will be
338
initialized by this function.  rec_offs_base(offsets)[0] will be set
339
to the extra size (if REC_OFFS_COMPACT is set, the record is in the
340
new format; if REC_OFFS_EXTERNAL is set, the record contains externally
341
stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to
342
offsets past the end of fields 0..n_fields, or to the beginning of
343
fields 1..n_fields+1.  When the high-order bit of the offset at [i+1]
344
is set (REC_OFFS_SQL_NULL), the field i is NULL.  When the second
345
high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
346
field i is being stored externally. */
347
static
348
void
349
rec_init_offsets(
350
/*=============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
351
	const rec_t*		rec,	/*!< in: physical record */
352
	const dict_index_t*	index,	/*!< in: record descriptor */
353
	ulint*			offsets)/*!< in/out: array of offsets;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
354
					in: n=rec_offs_n_fields(offsets) */
355
{
356
	ulint	i	= 0;
357
	ulint	offs;
358
359
	rec_offs_make_valid(rec, index, offsets);
360
361
	if (dict_table_is_comp(index->table)) {
362
		const byte*	nulls;
363
		const byte*	lens;
364
		dict_field_t*	field;
365
		ulint		null_mask;
366
		ulint		status = rec_get_status(rec);
367
		ulint		n_node_ptr_field = ULINT_UNDEFINED;
368
369
		switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
370
		case REC_STATUS_INFIMUM:
371
		case REC_STATUS_SUPREMUM:
372
			/* the field is 8 bytes long */
373
			rec_offs_base(offsets)[0]
374
				= REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
375
			rec_offs_base(offsets)[1] = 8;
376
			return;
377
		case REC_STATUS_NODE_PTR:
378
			n_node_ptr_field
379
				= dict_index_get_n_unique_in_tree(index);
380
			break;
381
		case REC_STATUS_ORDINARY:
382
			rec_init_offsets_comp_ordinary(rec,
383
						       REC_N_NEW_EXTRA_BYTES,
384
						       index, offsets);
385
			return;
386
		}
387
388
		nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
389
		lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
390
		offs = 0;
391
		null_mask = 1;
392
393
		/* read the lengths of fields 0..n */
394
		do {
395
			ulint	len;
396
			if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
397
				len = offs += 4;
398
				goto resolved;
399
			}
400
401
			field = dict_index_get_nth_field(index, i);
402
			if (!(dict_field_get_col(field)->prtype
403
			      & DATA_NOT_NULL)) {
404
				/* nullable field => read the null flag */
405
406
				if (UNIV_UNLIKELY(!(byte) null_mask)) {
407
					nulls--;
408
					null_mask = 1;
409
				}
410
411
				if (*nulls & null_mask) {
412
					null_mask <<= 1;
413
					/* No length is stored for NULL fields.
414
					We do not advance offs, and we set
415
					the length to zero and enable the
416
					SQL NULL flag in offsets[]. */
417
					len = offs | REC_OFFS_SQL_NULL;
418
					goto resolved;
419
				}
420
				null_mask <<= 1;
421
			}
422
423
			if (UNIV_UNLIKELY(!field->fixed_len)) {
424
				/* Variable-length field: read the length */
425
				const dict_col_t*	col
426
					= dict_field_get_col(field);
427
				len = *lens--;
428
				if (UNIV_UNLIKELY(col->len > 255)
429
				    || UNIV_UNLIKELY(col->mtype
430
						     == DATA_BLOB)) {
431
					if (len & 0x80) {
432
						/* 1exxxxxxx xxxxxxxx */
433
434
						len <<= 8;
435
						len |= *lens--;
436
437
						/* B-tree node pointers
438
						must not contain externally
439
						stored columns.  Thus
440
						the "e" flag must be 0. */
441
						ut_a(!(len & 0x4000));
442
						offs += len & 0x3fff;
443
						len = offs;
444
445
						goto resolved;
446
					}
447
				}
448
449
				len = offs += len;
450
			} else {
451
				len = offs += field->fixed_len;
452
			}
453
resolved:
454
			rec_offs_base(offsets)[i + 1] = len;
455
		} while (++i < rec_offs_n_fields(offsets));
456
457
		*rec_offs_base(offsets)
458
			= (rec - (lens + 1)) | REC_OFFS_COMPACT;
459
	} else {
460
		/* Old-style record: determine extra size and end offsets */
461
		offs = REC_N_OLD_EXTRA_BYTES;
462
		if (rec_get_1byte_offs_flag(rec)) {
463
			offs += rec_offs_n_fields(offsets);
464
			*rec_offs_base(offsets) = offs;
465
			/* Determine offsets to fields */
466
			do {
467
				offs = rec_1_get_field_end_info(rec, i);
468
				if (offs & REC_1BYTE_SQL_NULL_MASK) {
469
					offs &= ~REC_1BYTE_SQL_NULL_MASK;
470
					offs |= REC_OFFS_SQL_NULL;
471
				}
472
				rec_offs_base(offsets)[1 + i] = offs;
473
			} while (++i < rec_offs_n_fields(offsets));
474
		} else {
475
			offs += 2 * rec_offs_n_fields(offsets);
476
			*rec_offs_base(offsets) = offs;
477
			/* Determine offsets to fields */
478
			do {
479
				offs = rec_2_get_field_end_info(rec, i);
480
				if (offs & REC_2BYTE_SQL_NULL_MASK) {
481
					offs &= ~REC_2BYTE_SQL_NULL_MASK;
482
					offs |= REC_OFFS_SQL_NULL;
483
				}
484
				if (offs & REC_2BYTE_EXTERN_MASK) {
485
					offs &= ~REC_2BYTE_EXTERN_MASK;
486
					offs |= REC_OFFS_EXTERNAL;
487
					*rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
488
				}
489
				rec_offs_base(offsets)[1 + i] = offs;
490
			} while (++i < rec_offs_n_fields(offsets));
491
		}
492
	}
493
}
494
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
495
/******************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
496
The following function determines the offsets to each field
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
497
in the record.	It can reuse a previously returned array.
498
@return	the new offsets */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
499
UNIV_INTERN
500
ulint*
501
rec_get_offsets_func(
502
/*=================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
503
	const rec_t*		rec,	/*!< in: physical record */
504
	const dict_index_t*	index,	/*!< in: record descriptor */
505
	ulint*			offsets,/*!< in/out: array consisting of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
506
					offsets[0] allocated elements,
507
					or an array from rec_get_offsets(),
508
					or NULL */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
509
	ulint			n_fields,/*!< in: maximum number of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
510
					initialized fields
511
					 (ULINT_UNDEFINED if all fields) */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
512
	mem_heap_t**		heap,	/*!< in/out: memory heap */
513
	const char*		file,	/*!< in: file name where called */
514
	ulint			line)	/*!< in: line number where called */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
515
{
516
	ulint	n;
517
	ulint	size;
518
519
	ut_ad(rec);
520
	ut_ad(index);
521
	ut_ad(heap);
522
523
	if (dict_table_is_comp(index->table)) {
524
		switch (UNIV_EXPECT(rec_get_status(rec),
525
				    REC_STATUS_ORDINARY)) {
526
		case REC_STATUS_ORDINARY:
527
			n = dict_index_get_n_fields(index);
528
			break;
529
		case REC_STATUS_NODE_PTR:
530
			n = dict_index_get_n_unique_in_tree(index) + 1;
531
			break;
532
		case REC_STATUS_INFIMUM:
533
		case REC_STATUS_SUPREMUM:
534
			/* infimum or supremum record */
535
			n = 1;
536
			break;
537
		default:
538
			ut_error;
539
			return(NULL);
540
		}
541
	} else {
542
		n = rec_get_n_fields_old(rec);
543
	}
544
545
	if (UNIV_UNLIKELY(n_fields < n)) {
546
		n = n_fields;
547
	}
548
549
	size = n + (1 + REC_OFFS_HEADER_SIZE);
550
551
	if (UNIV_UNLIKELY(!offsets)
552
	    || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
553
		if (UNIV_UNLIKELY(!*heap)) {
554
			*heap = mem_heap_create_func(size * sizeof(ulint),
555
						     MEM_HEAP_DYNAMIC,
556
						     file, line);
557
		}
558
		offsets = mem_heap_alloc(*heap, size * sizeof(ulint));
559
		rec_offs_set_n_alloc(offsets, size);
560
	}
561
562
	rec_offs_set_n_fields(offsets, n);
563
	rec_init_offsets(rec, index, offsets);
564
	return(offsets);
565
}
566
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
567
/******************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
568
The following function determines the offsets to each field
569
in the record.  It can reuse a previously allocated array. */
570
UNIV_INTERN
571
void
572
rec_get_offsets_reverse(
573
/*====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
574
	const byte*		extra,	/*!< in: the extra bytes of a
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
575
					compact record in reverse order,
576
					excluding the fixed-size
577
					REC_N_NEW_EXTRA_BYTES */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
578
	const dict_index_t*	index,	/*!< in: record descriptor */
579
	ulint			node_ptr,/*!< in: nonzero=node pointer,
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
580
					0=leaf node */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
581
	ulint*			offsets)/*!< in/out: array consisting of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
582
					offsets[0] allocated elements */
583
{
584
	ulint		n;
585
	ulint		i;
586
	ulint		offs;
587
	ulint		any_ext;
588
	const byte*	nulls;
589
	const byte*	lens;
590
	dict_field_t*	field;
591
	ulint		null_mask;
592
	ulint		n_node_ptr_field;
593
594
	ut_ad(extra);
595
	ut_ad(index);
596
	ut_ad(offsets);
597
	ut_ad(dict_table_is_comp(index->table));
598
599
	if (UNIV_UNLIKELY(node_ptr)) {
600
		n_node_ptr_field = dict_index_get_n_unique_in_tree(index);
601
		n = n_node_ptr_field + 1;
602
	} else {
603
		n_node_ptr_field = ULINT_UNDEFINED;
604
		n = dict_index_get_n_fields(index);
605
	}
606
607
	ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
608
	rec_offs_set_n_fields(offsets, n);
609
610
	nulls = extra;
611
	lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
612
	i = offs = 0;
613
	null_mask = 1;
614
	any_ext = 0;
615
616
	/* read the lengths of fields 0..n */
617
	do {
618
		ulint	len;
619
		if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
620
			len = offs += 4;
621
			goto resolved;
622
		}
623
624
		field = dict_index_get_nth_field(index, i);
625
		if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
626
			/* nullable field => read the null flag */
627
628
			if (UNIV_UNLIKELY(!(byte) null_mask)) {
629
				nulls++;
630
				null_mask = 1;
631
			}
632
633
			if (*nulls & null_mask) {
634
				null_mask <<= 1;
635
				/* No length is stored for NULL fields.
636
				We do not advance offs, and we set
637
				the length to zero and enable the
638
				SQL NULL flag in offsets[]. */
639
				len = offs | REC_OFFS_SQL_NULL;
640
				goto resolved;
641
			}
642
			null_mask <<= 1;
643
		}
644
645
		if (UNIV_UNLIKELY(!field->fixed_len)) {
646
			/* Variable-length field: read the length */
647
			const dict_col_t*	col
648
				= dict_field_get_col(field);
649
			len = *lens++;
650
			if (UNIV_UNLIKELY(col->len > 255)
651
			    || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
652
				if (len & 0x80) {
653
					/* 1exxxxxxx xxxxxxxx */
654
					len <<= 8;
655
					len |= *lens++;
656
657
					offs += len & 0x3fff;
658
					if (UNIV_UNLIKELY(len & 0x4000)) {
659
						any_ext = REC_OFFS_EXTERNAL;
660
						len = offs | REC_OFFS_EXTERNAL;
661
					} else {
662
						len = offs;
663
					}
664
665
					goto resolved;
666
				}
667
			}
668
669
			len = offs += len;
670
		} else {
671
			len = offs += field->fixed_len;
672
		}
673
resolved:
674
		rec_offs_base(offsets)[i + 1] = len;
675
	} while (++i < rec_offs_n_fields(offsets));
676
677
	ut_ad(lens >= extra);
678
	*rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
679
		| REC_OFFS_COMPACT | any_ext;
680
}
681
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
682
/************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
683
The following function is used to get the offset to the nth
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
684
data field in an old-style record.
685
@return	offset to the field */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
686
UNIV_INTERN
687
ulint
688
rec_get_nth_field_offs_old(
689
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
690
	const rec_t*	rec,	/*!< in: record */
691
	ulint		n,	/*!< in: index of the field */
692
	ulint*		len)	/*!< out: length of the field;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
693
				UNIV_SQL_NULL if SQL null */
694
{
695
	ulint	os;
696
	ulint	next_os;
697
698
	ut_ad(rec && len);
699
	ut_ad(n < rec_get_n_fields_old(rec));
700
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
701
	if (UNIV_UNLIKELY(n > REC_MAX_N_FIELDS)) {
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
702
		fprintf(stderr, "Error: trying to access field %lu in rec\n",
703
			(ulong) n);
704
		ut_error;
705
	}
706
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
707
	if (UNIV_UNLIKELY(rec == NULL)) {
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
708
		fputs("Error: rec is NULL pointer\n", stderr);
709
		ut_error;
710
	}
711
712
	if (rec_get_1byte_offs_flag(rec)) {
713
		os = rec_1_get_field_start_offs(rec, n);
714
715
		next_os = rec_1_get_field_end_info(rec, n);
716
717
		if (next_os & REC_1BYTE_SQL_NULL_MASK) {
718
			*len = UNIV_SQL_NULL;
719
720
			return(os);
721
		}
722
723
		next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
724
	} else {
725
		os = rec_2_get_field_start_offs(rec, n);
726
727
		next_os = rec_2_get_field_end_info(rec, n);
728
729
		if (next_os & REC_2BYTE_SQL_NULL_MASK) {
730
			*len = UNIV_SQL_NULL;
731
732
			return(os);
733
		}
734
735
		next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
736
				      | REC_2BYTE_EXTERN_MASK);
737
	}
738
739
	*len = next_os - os;
740
741
	ut_ad(*len < UNIV_PAGE_SIZE);
742
743
	return(os);
744
}
745
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
746
/**********************************************************//**
747
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
748
@return	total size */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
749
UNIV_INTERN
750
ulint
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
751
rec_get_converted_size_comp_prefix(
752
/*===============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
753
	const dict_index_t*	index,	/*!< in: record descriptor;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
754
					dict_table_is_comp() is
755
					assumed to hold, even if
756
					it does not */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
757
	const dfield_t*		fields,	/*!< in: array of data fields */
758
	ulint			n_fields,/*!< in: number of data fields */
759
	ulint*			extra)	/*!< out: extra size */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
760
{
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
761
	ulint	extra_size;
762
	ulint	data_size;
763
	ulint	i;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
764
	ut_ad(index);
765
	ut_ad(fields);
766
	ut_ad(n_fields > 0);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
767
	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.
768
769
	extra_size = REC_N_NEW_EXTRA_BYTES
770
		+ UT_BITS_IN_BYTES(index->n_nullable);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
771
	data_size = 0;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
772
773
	/* read the lengths of fields 0..n */
774
	for (i = 0; i < n_fields; i++) {
775
		const dict_field_t*	field;
776
		ulint			len;
777
		const dict_col_t*	col;
778
779
		field = dict_index_get_nth_field(index, i);
780
		len = dfield_get_len(&fields[i]);
781
		col = dict_field_get_col(field);
782
783
		ut_ad(dict_col_type_assert_equal(col,
784
						 dfield_get_type(&fields[i])));
785
786
		if (dfield_is_null(&fields[i])) {
787
			/* No length is stored for NULL fields. */
788
			ut_ad(!(col->prtype & DATA_NOT_NULL));
789
			continue;
790
		}
791
792
		ut_ad(len <= col->len || col->mtype == DATA_BLOB);
793
794
		if (field->fixed_len) {
795
			ut_ad(len == field->fixed_len);
796
			/* dict_index_add_col() should guarantee this */
797
			ut_ad(!field->prefix_len
798
			      || field->fixed_len == field->prefix_len);
799
		} else if (dfield_is_ext(&fields[i])) {
800
			extra_size += 2;
801
		} else if (len < 128
802
			   || (col->len < 256 && col->mtype != DATA_BLOB)) {
803
			extra_size++;
804
		} else {
805
			/* For variable-length columns, we look up the
806
			maximum length from the column itself.  If this
807
			is a prefix index column shorter than 256 bytes,
808
			this will waste one byte. */
809
			extra_size += 2;
810
		}
811
		data_size += len;
812
	}
813
814
	if (UNIV_LIKELY_NULL(extra)) {
815
		*extra = extra_size;
816
	}
817
818
	return(extra_size + data_size);
819
}
820
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
821
/**********************************************************//**
822
Determines the size of a data tuple in ROW_FORMAT=COMPACT.
823
@return	total size */
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
824
UNIV_INTERN
825
ulint
826
rec_get_converted_size_comp(
827
/*========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
828
	const dict_index_t*	index,	/*!< in: record descriptor;
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
829
					dict_table_is_comp() is
830
					assumed to hold, even if
831
					it does not */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
832
	ulint			status,	/*!< in: status bits of the record */
833
	const dfield_t*		fields,	/*!< in: array of data fields */
834
	ulint			n_fields,/*!< in: number of data fields */
835
	ulint*			extra)	/*!< out: extra size */
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
836
{
837
	ulint	size;
838
	ut_ad(index);
839
	ut_ad(fields);
840
	ut_ad(n_fields > 0);
841
842
	switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
843
	case REC_STATUS_ORDINARY:
844
		ut_ad(n_fields == dict_index_get_n_fields(index));
845
		size = 0;
846
		break;
847
	case REC_STATUS_NODE_PTR:
848
		n_fields--;
849
		ut_ad(n_fields == dict_index_get_n_unique_in_tree(index));
850
		ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
851
		size = REC_NODE_PTR_SIZE; /* child page number */
852
		break;
853
	case REC_STATUS_INFIMUM:
854
	case REC_STATUS_SUPREMUM:
855
		/* infimum or supremum record, 8 data bytes */
856
		if (UNIV_LIKELY_NULL(extra)) {
857
			*extra = REC_N_NEW_EXTRA_BYTES;
858
		}
859
		return(REC_N_NEW_EXTRA_BYTES + 8);
860
	default:
861
		ut_error;
862
		return(ULINT_UNDEFINED);
863
	}
864
865
	return(size + rec_get_converted_size_comp_prefix(index, fields,
866
							 n_fields, extra));
867
}
868
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
869
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
870
Sets the value of the ith field SQL null bit of an old-style record. */
871
UNIV_INTERN
872
void
873
rec_set_nth_field_null_bit(
874
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
875
	rec_t*	rec,	/*!< in: record */
876
	ulint	i,	/*!< in: ith field */
877
	ibool	val)	/*!< in: value to set */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
878
{
879
	ulint	info;
880
881
	if (rec_get_1byte_offs_flag(rec)) {
882
883
		info = rec_1_get_field_end_info(rec, i);
884
885
		if (val) {
886
			info = info | REC_1BYTE_SQL_NULL_MASK;
887
		} else {
888
			info = info & ~REC_1BYTE_SQL_NULL_MASK;
889
		}
890
891
		rec_1_set_field_end_info(rec, i, info);
892
893
		return;
894
	}
895
896
	info = rec_2_get_field_end_info(rec, i);
897
898
	if (val) {
899
		info = info | REC_2BYTE_SQL_NULL_MASK;
900
	} else {
901
		info = info & ~REC_2BYTE_SQL_NULL_MASK;
902
	}
903
904
	rec_2_set_field_end_info(rec, i, info);
905
}
906
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
907
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
908
Sets an old-style record field to SQL null.
909
The physical size of the field is not changed. */
910
UNIV_INTERN
911
void
912
rec_set_nth_field_sql_null(
913
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
914
	rec_t*	rec,	/*!< in: record */
915
	ulint	n)	/*!< in: index of the field */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
916
{
917
	ulint	offset;
918
919
	offset = rec_get_field_start_offs(rec, n);
920
921
	data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
922
923
	rec_set_nth_field_null_bit(rec, n, TRUE);
924
}
925
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
926
/*********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
927
Builds an old-style physical record out of a data tuple and
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
928
stores it beginning from the start of the given buffer.
929
@return	pointer to the origin of physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
930
static
931
rec_t*
932
rec_convert_dtuple_to_rec_old(
933
/*==========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
934
	byte*		buf,	/*!< in: start address of the physical record */
935
	const dtuple_t*	dtuple,	/*!< in: data tuple */
936
	ulint		n_ext)	/*!< in: number of externally stored columns */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
937
{
938
	const dfield_t*	field;
939
	ulint		n_fields;
940
	ulint		data_size;
941
	rec_t*		rec;
942
	ulint		end_offset;
943
	ulint		ored_offset;
944
	ulint		len;
945
	ulint		i;
946
947
	ut_ad(buf && dtuple);
948
	ut_ad(dtuple_validate(dtuple));
949
	ut_ad(dtuple_check_typed(dtuple));
950
951
	n_fields = dtuple_get_n_fields(dtuple);
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
952
	data_size = dtuple_get_data_size(dtuple, 0);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
953
954
	ut_ad(n_fields > 0);
955
956
	/* Calculate the offset of the origin in the physical record */
957
958
	rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
959
#ifdef UNIV_DEBUG
960
	/* Suppress Valgrind warnings of ut_ad()
961
	in mach_write_to_1(), mach_write_to_2() et al. */
962
	memset(buf, 0xff, rec - buf + data_size);
963
#endif /* UNIV_DEBUG */
964
	/* Store the number of fields */
965
	rec_set_n_fields_old(rec, n_fields);
966
967
	/* Set the info bits of the record */
968
	rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
969
			      & REC_INFO_BITS_MASK);
970
971
	/* Store the data and the offsets */
972
973
	end_offset = 0;
974
975
	if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
976
977
		rec_set_1byte_offs_flag(rec, TRUE);
978
979
		for (i = 0; i < n_fields; i++) {
980
981
			field = dtuple_get_nth_field(dtuple, i);
982
983
			if (dfield_is_null(field)) {
984
				len = dtype_get_sql_null_size(
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
985
					dfield_get_type(field), 0);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
986
				data_write_sql_null(rec + end_offset, len);
987
988
				end_offset += len;
989
				ored_offset = end_offset
990
					| REC_1BYTE_SQL_NULL_MASK;
991
			} else {
992
				/* If the data is not SQL null, store it */
993
				len = dfield_get_len(field);
994
995
				memcpy(rec + end_offset,
996
				       dfield_get_data(field), len);
997
998
				end_offset += len;
999
				ored_offset = end_offset;
1000
			}
1001
1002
			rec_1_set_field_end_info(rec, i, ored_offset);
1003
		}
1004
	} else {
1005
		rec_set_1byte_offs_flag(rec, FALSE);
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_2BYTE_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
				if (dfield_is_ext(field)) {
1030
					ored_offset |= REC_2BYTE_EXTERN_MASK;
1031
				}
1032
			}
1033
1034
			rec_2_set_field_end_info(rec, i, ored_offset);
1035
		}
1036
	}
1037
1038
	return(rec);
1039
}
1040
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1041
/*********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1042
Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
1043
UNIV_INTERN
1044
void
1045
rec_convert_dtuple_to_rec_comp(
1046
/*===========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1047
	rec_t*			rec,	/*!< in: origin of record */
1048
	ulint			extra,	/*!< in: number of bytes to
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1049
					reserve between the record
1050
					header and the data payload
1051
					(normally REC_N_NEW_EXTRA_BYTES) */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1052
	const dict_index_t*	index,	/*!< in: record descriptor */
1053
	ulint			status,	/*!< in: status bits of the record */
1054
	const dfield_t*		fields,	/*!< in: array of data fields */
1055
	ulint			n_fields)/*!< in: number of data fields */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1056
{
1057
	const dfield_t*	field;
1058
	const dtype_t*	type;
1059
	byte*		end;
1060
	byte*		nulls;
1061
	byte*		lens;
1062
	ulint		len;
1063
	ulint		i;
1064
	ulint		n_node_ptr_field;
1065
	ulint		fixed_len;
1066
	ulint		null_mask	= 1;
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
1067
	ut_ad(extra == 0 || dict_table_is_comp(index->table));
1068
	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.
1069
	ut_ad(n_fields > 0);
1070
1071
	switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
1072
	case REC_STATUS_ORDINARY:
1073
		ut_ad(n_fields <= dict_index_get_n_fields(index));
1074
		n_node_ptr_field = ULINT_UNDEFINED;
1075
		break;
1076
	case REC_STATUS_NODE_PTR:
1077
		ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
1078
		n_node_ptr_field = n_fields - 1;
1079
		break;
1080
	case REC_STATUS_INFIMUM:
1081
	case REC_STATUS_SUPREMUM:
1082
		ut_ad(n_fields == 1);
1083
		n_node_ptr_field = ULINT_UNDEFINED;
1084
		break;
1085
	default:
1086
		ut_error;
1087
		return;
1088
	}
1089
1090
	end = rec;
1091
	nulls = rec - (extra + 1);
1092
	lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1093
	/* clear the SQL-null flags */
1094
	memset(lens + 1, 0, nulls - lens);
1095
1096
	/* Store the data and the offsets */
1097
1098
	for (i = 0, field = fields; i < n_fields; i++, field++) {
1099
		type = dfield_get_type(field);
1100
		len = dfield_get_len(field);
1101
1102
		if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
1103
			ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
1104
			ut_ad(len == 4);
1105
			memcpy(end, dfield_get_data(field), len);
1106
			end += 4;
1107
			break;
1108
		}
1109
1110
		if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
1111
			/* nullable field */
1112
			ut_ad(index->n_nullable > 0);
1113
1114
			if (UNIV_UNLIKELY(!(byte) null_mask)) {
1115
				nulls--;
1116
				null_mask = 1;
1117
			}
1118
1119
			ut_ad(*nulls < null_mask);
1120
1121
			/* set the null flag if necessary */
1122
			if (dfield_is_null(field)) {
1123
				*nulls |= null_mask;
1124
				null_mask <<= 1;
1125
				continue;
1126
			}
1127
1128
			null_mask <<= 1;
1129
		}
1130
		/* only nullable fields can be null */
1131
		ut_ad(!dfield_is_null(field));
1132
1133
		fixed_len = dict_index_get_nth_field(index, i)->fixed_len;
1134
1135
		if (fixed_len) {
1136
			ut_ad(len == fixed_len);
1137
			ut_ad(!dfield_is_ext(field));
1138
		} else if (dfield_is_ext(field)) {
1139
			ut_ad(len <= REC_MAX_INDEX_COL_LEN
1140
			      + BTR_EXTERN_FIELD_REF_SIZE);
1141
			*lens-- = (byte) (len >> 8) | 0xc0;
1142
			*lens-- = (byte) len;
1143
		} else {
1144
			ut_ad(len <= dtype_get_len(type)
1145
			      || dtype_get_mtype(type) == DATA_BLOB);
1146
			if (len < 128
1147
			    || (dtype_get_len(type) < 256
1148
				&& dtype_get_mtype(type) != DATA_BLOB)) {
1149
1150
				*lens-- = (byte) len;
1151
			} else {
1152
				ut_ad(len < 16384);
1153
				*lens-- = (byte) (len >> 8) | 0x80;
1154
				*lens-- = (byte) len;
1155
			}
1156
		}
1157
1158
		memcpy(end, dfield_get_data(field), len);
1159
		end += len;
1160
	}
1161
}
1162
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1163
/*********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1164
Builds a new-style physical record out of a data tuple and
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1165
stores it beginning from the start of the given buffer.
1166
@return	pointer to the origin of physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1167
static
1168
rec_t*
1169
rec_convert_dtuple_to_rec_new(
1170
/*==========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1171
	byte*			buf,	/*!< in: start address of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1172
					the physical record */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1173
	const dict_index_t*	index,	/*!< in: record descriptor */
1174
	const dtuple_t*		dtuple)	/*!< in: data tuple */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1175
{
1176
	ulint	extra_size;
1177
	ulint	status;
1178
	rec_t*	rec;
1179
1180
	status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK;
1181
	rec_get_converted_size_comp(index, status,
1182
				    dtuple->fields, dtuple->n_fields,
1183
				    &extra_size);
1184
	rec = buf + extra_size;
1185
1186
	rec_convert_dtuple_to_rec_comp(
1187
		rec, REC_N_NEW_EXTRA_BYTES, index, status,
1188
		dtuple->fields, dtuple->n_fields);
1189
1190
	/* Set the info bits of the record */
1191
	rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
1192
1193
	return(rec);
1194
}
1195
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1196
/*********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1197
Builds a physical record out of a data tuple and
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1198
stores it beginning from the start of the given buffer.
1199
@return	pointer to the origin of physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1200
UNIV_INTERN
1201
rec_t*
1202
rec_convert_dtuple_to_rec(
1203
/*======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1204
	byte*			buf,	/*!< in: start address of the
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1205
					physical record */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1206
	const dict_index_t*	index,	/*!< in: record descriptor */
1207
	const dtuple_t*		dtuple,	/*!< in: data tuple */
1208
	ulint			n_ext)	/*!< in: number of
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1209
					externally stored columns */
1210
{
1211
	rec_t*	rec;
1212
1213
	ut_ad(buf && index && dtuple);
1214
	ut_ad(dtuple_validate(dtuple));
1215
	ut_ad(dtuple_check_typed(dtuple));
1216
1217
	if (dict_table_is_comp(index->table)) {
1218
		rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
1219
	} else {
1220
		rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
1221
	}
1222
1223
#ifdef UNIV_DEBUG
1224
	{
1225
		mem_heap_t*	heap	= NULL;
1226
		ulint		offsets_[REC_OFFS_NORMAL_SIZE];
1227
		const ulint*	offsets;
1228
		rec_offs_init(offsets_);
1229
1230
		offsets = rec_get_offsets(rec, index,
1231
					  offsets_, ULINT_UNDEFINED, &heap);
1232
		ut_ad(rec_validate(rec, offsets));
1233
		if (UNIV_LIKELY_NULL(heap)) {
1234
			mem_heap_free(heap);
1235
		}
1236
	}
1237
#endif /* UNIV_DEBUG */
1238
	return(rec);
1239
}
1240
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1241
/**************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1242
Copies the first n fields of a physical record to a data tuple. The fields
1243
are copied to the memory heap. */
1244
UNIV_INTERN
1245
void
1246
rec_copy_prefix_to_dtuple(
1247
/*======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1248
	dtuple_t*		tuple,		/*!< out: data tuple */
1249
	const rec_t*		rec,		/*!< in: physical record */
1250
	const dict_index_t*	index,		/*!< in: record descriptor */
1251
	ulint			n_fields,	/*!< in: number of fields
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1252
						to copy */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1253
	mem_heap_t*		heap)		/*!< in: memory heap */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1254
{
1255
	ulint	i;
1256
	ulint	offsets_[REC_OFFS_NORMAL_SIZE];
1257
	ulint*	offsets	= offsets_;
1258
	rec_offs_init(offsets_);
1259
1260
	offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
1261
1262
	ut_ad(rec_validate(rec, offsets));
1263
	ut_ad(dtuple_check_typed(tuple));
1264
1265
	dtuple_set_info_bits(tuple, rec_get_info_bits(
1266
				     rec, dict_table_is_comp(index->table)));
1267
1268
	for (i = 0; i < n_fields; i++) {
1269
		dfield_t*	field;
1270
		const byte*	data;
1271
		ulint		len;
1272
1273
		field = dtuple_get_nth_field(tuple, i);
1274
		data = rec_get_nth_field(rec, offsets, i, &len);
1275
1276
		if (len != UNIV_SQL_NULL) {
1277
			dfield_set_data(field,
1278
					mem_heap_dup(heap, data, len), len);
1279
			ut_ad(!rec_offs_nth_extern(offsets, i));
1280
		} else {
1281
			dfield_set_null(field);
1282
		}
1283
	}
1284
}
1285
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1286
/**************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1287
Copies the first n fields of an old-style physical record
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1288
to a new physical record in a buffer.
1289
@return	own: copied record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1290
static
1291
rec_t*
1292
rec_copy_prefix_to_buf_old(
1293
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1294
	const rec_t*	rec,		/*!< in: physical record */
1295
	ulint		n_fields,	/*!< in: number of fields to copy */
1296
	ulint		area_end,	/*!< in: end of the prefix data */
1297
	byte**		buf,		/*!< in/out: memory buffer for
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1298
					the copied prefix, or NULL */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1299
	ulint*		buf_size)	/*!< in/out: buffer size */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1300
{
1301
	rec_t*	copy_rec;
1302
	ulint	area_start;
1303
	ulint	prefix_len;
1304
1305
	if (rec_get_1byte_offs_flag(rec)) {
1306
		area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
1307
	} else {
1308
		area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
1309
	}
1310
1311
	prefix_len = area_start + area_end;
1312
1313
	if ((*buf == NULL) || (*buf_size < prefix_len)) {
1314
		if (*buf != NULL) {
1315
			mem_free(*buf);
1316
		}
1317
1318
		*buf = mem_alloc2(prefix_len, buf_size);
1319
	}
1320
1321
	ut_memcpy(*buf, rec - area_start, prefix_len);
1322
1323
	copy_rec = *buf + area_start;
1324
1325
	rec_set_n_fields_old(copy_rec, n_fields);
1326
1327
	return(copy_rec);
1328
}
1329
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1330
/**************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1331
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
1332
a buffer.
1333
@return	own: copied record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1334
UNIV_INTERN
1335
rec_t*
1336
rec_copy_prefix_to_buf(
1337
/*===================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1338
	const rec_t*		rec,		/*!< in: physical record */
1339
	const dict_index_t*	index,		/*!< in: record descriptor */
1340
	ulint			n_fields,	/*!< in: number of fields
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1341
						to copy */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1342
	byte**			buf,		/*!< in/out: memory buffer
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1343
						for the copied prefix,
1344
						or NULL */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1345
	ulint*			buf_size)	/*!< in/out: buffer size */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1346
{
1347
	const byte*	nulls;
1348
	const byte*	lens;
1349
	ulint		i;
1350
	ulint		prefix_len;
1351
	ulint		null_mask;
1352
	ulint		status;
1353
1354
	UNIV_PREFETCH_RW(*buf);
1355
1356
	if (!dict_table_is_comp(index->table)) {
1357
		ut_ad(rec_validate_old(rec));
1358
		return(rec_copy_prefix_to_buf_old(
1359
			       rec, n_fields,
1360
			       rec_get_field_start_offs(rec, n_fields),
1361
			       buf, buf_size));
1362
	}
1363
1364
	status = rec_get_status(rec);
1365
1366
	switch (status) {
1367
	case REC_STATUS_ORDINARY:
1368
		ut_ad(n_fields <= dict_index_get_n_fields(index));
1369
		break;
1370
	case REC_STATUS_NODE_PTR:
1371
		/* it doesn't make sense to copy the child page number field */
1372
		ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
1373
		break;
1374
	case REC_STATUS_INFIMUM:
1375
	case REC_STATUS_SUPREMUM:
1376
		/* infimum or supremum record: no sense to copy anything */
1377
	default:
1378
		ut_error;
1379
		return(NULL);
1380
	}
1381
1382
	nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
1383
	lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
1384
	UNIV_PREFETCH_R(lens);
1385
	prefix_len = 0;
1386
	null_mask = 1;
1387
1388
	/* read the lengths of fields 0..n */
1389
	for (i = 0; i < n_fields; i++) {
1390
		const dict_field_t*	field;
1391
		const dict_col_t*	col;
1392
1393
		field = dict_index_get_nth_field(index, i);
1394
		col = dict_field_get_col(field);
1395
1396
		if (!(col->prtype & DATA_NOT_NULL)) {
1397
			/* nullable field => read the null flag */
1398
			if (UNIV_UNLIKELY(!(byte) null_mask)) {
1399
				nulls--;
1400
				null_mask = 1;
1401
			}
1402
1403
			if (*nulls & null_mask) {
1404
				null_mask <<= 1;
1405
				continue;
1406
			}
1407
1408
			null_mask <<= 1;
1409
		}
1410
1411
		if (field->fixed_len) {
1412
			prefix_len += field->fixed_len;
1413
		} else {
1414
			ulint	len = *lens--;
1415
			if (col->len > 255 || col->mtype == DATA_BLOB) {
1416
				if (len & 0x80) {
1417
					/* 1exxxxxx */
1418
					len &= 0x3f;
1419
					len <<= 8;
1420
					len |= *lens--;
1421
					UNIV_PREFETCH_R(lens);
1422
				}
1423
			}
1424
			prefix_len += len;
1425
		}
1426
	}
1427
1428
	UNIV_PREFETCH_R(rec + prefix_len);
1429
1430
	prefix_len += rec - (lens + 1);
1431
1432
	if ((*buf == NULL) || (*buf_size < prefix_len)) {
1433
		if (*buf != NULL) {
1434
			mem_free(*buf);
1435
		}
1436
1437
		*buf = mem_alloc2(prefix_len, buf_size);
1438
	}
1439
1440
	memcpy(*buf, lens + 1, prefix_len);
1441
1442
	return(*buf + (rec - (lens + 1)));
1443
}
1444
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1445
/***************************************************************//**
1446
Validates the consistency of an old-style physical record.
1447
@return	TRUE if ok */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1448
static
1449
ibool
1450
rec_validate_old(
1451
/*=============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1452
	const rec_t*	rec)	/*!< in: physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1453
{
1454
	const byte*	data;
1455
	ulint		len;
1456
	ulint		n_fields;
1457
	ulint		len_sum		= 0;
1458
	ulint		sum		= 0;
1459
	ulint		i;
1460
1461
	ut_a(rec);
1462
	n_fields = rec_get_n_fields_old(rec);
1463
1464
	if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1465
		fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1466
			(ulong) n_fields);
1467
		return(FALSE);
1468
	}
1469
1470
	for (i = 0; i < n_fields; i++) {
1471
		data = rec_get_nth_field_old(rec, i, &len);
1472
1473
		if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1474
			fprintf(stderr,
1475
				"InnoDB: Error: record field %lu len %lu\n",
1476
				(ulong) i,
1477
				(ulong) len);
1478
			return(FALSE);
1479
		}
1480
1481
		if (len != UNIV_SQL_NULL) {
1482
			len_sum += len;
1483
			sum += *(data + len -1); /* dereference the
1484
						 end of the field to
1485
						 cause a memory trap
1486
						 if possible */
1487
		} else {
1488
			len_sum += rec_get_nth_field_size(rec, i);
1489
		}
1490
	}
1491
1492
	if (len_sum != rec_get_data_size_old(rec)) {
1493
		fprintf(stderr,
1494
			"InnoDB: Error: record len should be %lu, len %lu\n",
1495
			(ulong) len_sum,
1496
			rec_get_data_size_old(rec));
1497
		return(FALSE);
1498
	}
1499
1500
	rec_dummy = sum; /* This is here only to fool the compiler */
1501
1502
	return(TRUE);
1503
}
1504
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1505
/***************************************************************//**
1506
Validates the consistency of a physical record.
1507
@return	TRUE if ok */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1508
UNIV_INTERN
1509
ibool
1510
rec_validate(
1511
/*=========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1512
	const rec_t*	rec,	/*!< in: physical record */
1513
	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.
1514
{
1515
	const byte*	data;
1516
	ulint		len;
1517
	ulint		n_fields;
1518
	ulint		len_sum		= 0;
1519
	ulint		sum		= 0;
1520
	ulint		i;
1521
1522
	ut_a(rec);
1523
	n_fields = rec_offs_n_fields(offsets);
1524
1525
	if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
1526
		fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
1527
			(ulong) n_fields);
1528
		return(FALSE);
1529
	}
1530
1531
	ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
1532
1533
	for (i = 0; i < n_fields; i++) {
1534
		data = rec_get_nth_field(rec, offsets, i, &len);
1535
1536
		if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
1537
			fprintf(stderr,
1538
				"InnoDB: Error: record field %lu len %lu\n",
1539
				(ulong) i,
1540
				(ulong) len);
1541
			return(FALSE);
1542
		}
1543
1544
		if (len != UNIV_SQL_NULL) {
1545
			len_sum += len;
1546
			sum += *(data + len -1); /* dereference the
1547
						 end of the field to
1548
						 cause a memory trap
1549
						 if possible */
1550
		} else if (!rec_offs_comp(offsets)) {
1551
			len_sum += rec_get_nth_field_size(rec, i);
1552
		}
1553
	}
1554
1555
	if (len_sum != rec_offs_data_size(offsets)) {
1556
		fprintf(stderr,
1557
			"InnoDB: Error: record len should be %lu, len %lu\n",
1558
			(ulong) len_sum,
1559
			(ulong) rec_offs_data_size(offsets));
1560
		return(FALSE);
1561
	}
1562
1563
	rec_dummy = sum; /* This is here only to fool the compiler */
1564
1565
	if (!rec_offs_comp(offsets)) {
1566
		ut_a(rec_validate_old(rec));
1567
	}
1568
1569
	return(TRUE);
1570
}
1571
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1572
/***************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1573
Prints an old-style physical record. */
1574
UNIV_INTERN
1575
void
1576
rec_print_old(
1577
/*==========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1578
	FILE*		file,	/*!< in: file where to print */
1579
	const rec_t*	rec)	/*!< in: physical record */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1580
{
1581
	const byte*	data;
1582
	ulint		len;
1583
	ulint		n;
1584
	ulint		i;
1585
1586
	ut_ad(rec);
1587
1588
	n = rec_get_n_fields_old(rec);
1589
1590
	fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1591
		" %u-byte offsets; info bits %lu\n",
1592
		(ulong) n,
1593
		rec_get_1byte_offs_flag(rec) ? 1 : 2,
1594
		(ulong) rec_get_info_bits(rec, FALSE));
1595
1596
	for (i = 0; i < n; i++) {
1597
1598
		data = rec_get_nth_field_old(rec, i, &len);
1599
1600
		fprintf(file, " %lu:", (ulong) i);
1601
1602
		if (len != UNIV_SQL_NULL) {
1603
			if (len <= 30) {
1604
1605
				ut_print_buf(file, data, len);
1606
			} else {
1607
				ut_print_buf(file, data, 30);
1608
1609
				fprintf(file, " (total %lu bytes)",
1610
					(ulong) len);
1611
			}
1612
		} else {
1613
			fprintf(file, " SQL NULL, size %lu ",
1614
				rec_get_nth_field_size(rec, i));
1615
		}
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1616
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1617
		putc(';', file);
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1618
		putc('\n', file);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1619
	}
1620
1621
	rec_validate_old(rec);
1622
}
1623
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1624
#ifndef UNIV_HOTBACKUP
1625
/***************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1626
Prints a physical record in ROW_FORMAT=COMPACT.  Ignores the
1627
record header. */
1628
UNIV_INTERN
1629
void
1630
rec_print_comp(
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 */
1634
	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.
1635
{
1636
	ulint	i;
1637
1638
	for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1639
		const byte*	data;
1640
		ulint		len;
1641
1642
		data = rec_get_nth_field(rec, offsets, i, &len);
1643
1644
		fprintf(file, " %lu:", (ulong) i);
1645
1646
		if (len != UNIV_SQL_NULL) {
1647
			if (len <= 30) {
1648
1649
				ut_print_buf(file, data, len);
1650
			} else {
1651
				ut_print_buf(file, data, 30);
1652
1653
				fprintf(file, " (total %lu bytes)",
1654
					(ulong) len);
1655
			}
1656
		} else {
1657
			fputs(" SQL NULL", file);
1658
		}
1659
		putc(';', file);
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1660
		putc('\n', file);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1661
	}
1662
}
1663
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1664
/***************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1665
Prints a physical record. */
1666
UNIV_INTERN
1667
void
1668
rec_print_new(
1669
/*==========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1670
	FILE*		file,	/*!< in: file where to print */
1671
	const rec_t*	rec,	/*!< in: physical record */
1672
	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.
1673
{
1674
	ut_ad(rec);
1675
	ut_ad(offsets);
1676
	ut_ad(rec_offs_validate(rec, NULL, offsets));
1677
1678
	if (!rec_offs_comp(offsets)) {
1679
		rec_print_old(file, rec);
1680
		return;
1681
	}
1682
1683
	fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
1684
		" compact format; info bits %lu\n",
1685
		(ulong) rec_offs_n_fields(offsets),
1686
		(ulong) rec_get_info_bits(rec, TRUE));
1687
1688
	rec_print_comp(file, rec, offsets);
1689
	rec_validate(rec, offsets);
1690
}
1691
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1692
/***************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1693
Prints a physical record. */
1694
UNIV_INTERN
1695
void
1696
rec_print(
1697
/*======*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1698
	FILE*		file,	/*!< in: file where to print */
1699
	const rec_t*	rec,	/*!< in: physical record */
1700
	dict_index_t*	index)	/*!< in: record descriptor */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1701
{
1702
	ut_ad(index);
1703
1704
	if (!dict_table_is_comp(index->table)) {
1705
		rec_print_old(file, rec);
1706
		return;
1707
	} else {
1708
		mem_heap_t*	heap	= NULL;
1709
		ulint		offsets_[REC_OFFS_NORMAL_SIZE];
1710
		rec_offs_init(offsets_);
1711
1712
		rec_print_new(file, rec,
1713
			      rec_get_offsets(rec, index, offsets_,
1714
					      ULINT_UNDEFINED, &heap));
1715
		if (UNIV_LIKELY_NULL(heap)) {
1716
			mem_heap_free(heap);
1717
		}
1718
	}
1719
}
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1720
#endif /* !UNIV_HOTBACKUP */