~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/************************************************************************
2
Record manager
3
4
(c) 1994-1996 Innobase Oy
5
6
Created 5/30/1994 Heikki Tuuri
7
*************************************************************************/
8
9
#include "mach0data.h"
10
#include "ut0byte.h"
11
#include "dict0dict.h"
12
13
/* Compact flag ORed to the extra size returned by rec_get_offsets() */
14
#define REC_OFFS_COMPACT	((ulint) 1 << 31)
15
/* SQL NULL flag in offsets returned by rec_get_offsets() */
16
#define REC_OFFS_SQL_NULL	((ulint) 1 << 31)
17
/* External flag in offsets returned by rec_get_offsets() */
18
#define REC_OFFS_EXTERNAL	((ulint) 1 << 30)
19
/* Mask for offsets returned by rec_get_offsets() */
20
#define REC_OFFS_MASK		(REC_OFFS_EXTERNAL - 1)
21
22
/* Offsets of the bit-fields in an old-style record. NOTE! In the table the
23
most significant bytes and bits are written below less significant.
24
25
	(1) byte offset		(2) bit usage within byte
26
	downward from
27
	origin ->	1	8 bits pointer to next record
28
			2	8 bits pointer to next record
29
			3	1 bit short flag
30
				7 bits number of fields
31
			4	3 bits number of fields
32
				5 bits heap number
33
			5	8 bits heap number
34
			6	4 bits n_owned
35
				4 bits info bits
36
*/
37
38
/* Offsets of the bit-fields in a new-style record. NOTE! In the table the
39
most significant bytes and bits are written below less significant.
40
41
	(1) byte offset		(2) bit usage within byte
42
	downward from
43
	origin ->	1	8 bits relative offset of next record
44
			2	8 bits relative offset of next record
45
				  the relative offset is an unsigned 16-bit
46
				  integer:
47
				  (offset_of_next_record
48
				   - offset_of_this_record) mod 64Ki,
49
				  where mod is the modulo as a non-negative
50
				  number;
51
				  we can calculate the the offset of the next
52
				  record with the formula:
53
				  relative_offset + offset_of_this_record
54
				  mod UNIV_PAGE_SIZE
55
			3	3 bits status:
56
					000=conventional record
57
					001=node pointer record (inside B-tree)
58
					010=infimum record
59
					011=supremum record
60
					1xx=reserved
61
				5 bits heap number
62
			4	8 bits heap number
63
			5	4 bits n_owned
64
				4 bits info bits
65
*/
66
67
/* We list the byte offsets from the origin of the record, the mask,
68
and the shift needed to obtain each bit-field of the record. */
69
70
#define REC_NEXT		2
71
#define REC_NEXT_MASK		0xFFFFUL
72
#define REC_NEXT_SHIFT		0
73
74
#define REC_OLD_SHORT		3	/* This is single byte bit-field */
75
#define REC_OLD_SHORT_MASK	0x1UL
76
#define REC_OLD_SHORT_SHIFT	0
77
78
#define REC_OLD_N_FIELDS	4
79
#define REC_OLD_N_FIELDS_MASK	0x7FEUL
80
#define REC_OLD_N_FIELDS_SHIFT	1
81
82
#define REC_NEW_STATUS		3	/* This is single byte bit-field */
83
#define REC_NEW_STATUS_MASK	0x7UL
84
#define REC_NEW_STATUS_SHIFT	0
85
86
#define REC_OLD_HEAP_NO		5
87
#define REC_NEW_HEAP_NO		4
88
#define REC_HEAP_NO_MASK	0xFFF8UL
89
#define	REC_HEAP_NO_SHIFT	3
90
91
#define REC_OLD_N_OWNED		6	/* This is single byte bit-field */
92
#define REC_NEW_N_OWNED		5	/* This is single byte bit-field */
93
#define	REC_N_OWNED_MASK	0xFUL
94
#define REC_N_OWNED_SHIFT	0
95
96
#define REC_OLD_INFO_BITS	6	/* This is single byte bit-field */
97
#define REC_NEW_INFO_BITS	5	/* This is single byte bit-field */
98
#define	REC_INFO_BITS_MASK	0xF0UL
99
#define REC_INFO_BITS_SHIFT	0
100
101
/* The deleted flag in info bits */
102
#define REC_INFO_DELETED_FLAG	0x20UL	/* when bit is set to 1, it means the
103
					record has been delete marked */
104
/* The following masks are used to filter the SQL null bit from
105
one-byte and two-byte offsets */
106
107
#define REC_1BYTE_SQL_NULL_MASK	0x80UL
108
#define REC_2BYTE_SQL_NULL_MASK	0x8000UL
109
110
/* In a 2-byte offset the second most significant bit denotes
111
a field stored to another page: */
112
113
#define REC_2BYTE_EXTERN_MASK	0x4000UL
114
115
#if REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) \
116
		^ REC_OLD_N_FIELDS_MASK << (8 * (REC_OLD_N_FIELDS - 4)) \
117
		^ REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) \
118
		^ REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) \
119
		^ REC_INFO_BITS_MASK << (8 * (REC_OLD_INFO_BITS - 3)) \
120
		^ 0xFFFFFFFFUL
121
# error "sum of old-style masks != 0xFFFFFFFFUL"
122
#endif
123
#if REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) \
124
		^ REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) \
125
		^ REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) \
126
		^ REC_INFO_BITS_MASK << (8 * (REC_NEW_INFO_BITS - 3)) \
127
		^ 0xFFFFFFUL
128
# error "sum of new-style masks != 0xFFFFFFUL"
129
#endif
130
131
/***************************************************************
132
Sets the value of the ith field SQL null bit of an old-style record. */
133
134
void
135
rec_set_nth_field_null_bit(
136
/*=======================*/
137
	rec_t*	rec,	/* in: record */
138
	ulint	i,	/* in: ith field */
139
	ibool	val);	/* in: value to set */
140
/***************************************************************
141
Sets an old-style record field to SQL null.
142
The physical size of the field is not changed. */
143
144
void
145
rec_set_nth_field_sql_null(
146
/*=======================*/
147
	rec_t*	rec,	/* in: record */
148
	ulint	n);	/* in: index of the field */
149
150
/***************************************************************
151
Sets the value of the ith field extern storage bit of an old-style record. */
152
153
void
154
rec_set_nth_field_extern_bit_old(
155
/*=============================*/
156
	rec_t*	rec,	/* in: old-style record */
157
	ulint	i,	/* in: ith field */
158
	ibool	val,	/* in: value to set */
159
	mtr_t*	mtr);	/* in: mtr holding an X-latch to the page where
160
			rec is, or NULL; in the NULL case we do not
161
			write to log about the change */
162
/***************************************************************
163
Sets the value of the ith field extern storage bit of a new-style record. */
164
165
void
166
rec_set_nth_field_extern_bit_new(
167
/*=============================*/
168
	rec_t*		rec,	/* in: record */
169
	dict_index_t*	index,	/* in: record descriptor */
170
	ulint		ith,	/* in: ith field */
171
	ibool		val,	/* in: value to set */
172
	mtr_t*		mtr);	/* in: mtr holding an X-latch to the page
173
				where rec is, or NULL; in the NULL case
174
				we do not write to log about the change */
175
176
/**********************************************************
177
Gets a bit field from within 1 byte. */
178
UNIV_INLINE
179
ulint
180
rec_get_bit_field_1(
181
/*================*/
182
	rec_t*	rec,	/* in: pointer to record origin */
183
	ulint	offs,	/* in: offset from the origin down */
184
	ulint	mask,	/* in: mask used to filter bits */
185
	ulint	shift)	/* in: shift right applied after masking */
186
{
187
	ut_ad(rec);
188
189
	return((mach_read_from_1(rec - offs) & mask) >> shift);
190
}
191
192
/**********************************************************
193
Sets a bit field within 1 byte. */
194
UNIV_INLINE
195
void
196
rec_set_bit_field_1(
197
/*================*/
198
	rec_t*	rec,	/* in: pointer to record origin */
199
	ulint	val,	/* in: value to set */
200
	ulint	offs,	/* in: offset from the origin down */
201
	ulint	mask,	/* in: mask used to filter bits */
202
	ulint	shift)	/* in: shift right applied after masking */
203
{
204
	ut_ad(rec);
205
	ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
206
	ut_ad(mask);
207
	ut_ad(mask <= 0xFFUL);
208
	ut_ad(((mask >> shift) << shift) == mask);
209
	ut_ad(((val << shift) & mask) == (val << shift));
210
211
	mach_write_to_1(rec - offs,
212
			(mach_read_from_1(rec - offs) & ~mask)
213
			| (val << shift));
214
}
215
216
/**********************************************************
217
Gets a bit field from within 2 bytes. */
218
UNIV_INLINE
219
ulint
220
rec_get_bit_field_2(
221
/*================*/
222
	rec_t*	rec,	/* in: pointer to record origin */
223
	ulint	offs,	/* in: offset from the origin down */
224
	ulint	mask,	/* in: mask used to filter bits */
225
	ulint	shift)	/* in: shift right applied after masking */
226
{
227
	ut_ad(rec);
228
229
	return((mach_read_from_2(rec - offs) & mask) >> shift);
230
}
231
232
/**********************************************************
233
Sets a bit field within 2 bytes. */
234
UNIV_INLINE
235
void
236
rec_set_bit_field_2(
237
/*================*/
238
	rec_t*	rec,	/* in: pointer to record origin */
239
	ulint	val,	/* in: value to set */
240
	ulint	offs,	/* in: offset from the origin down */
241
	ulint	mask,	/* in: mask used to filter bits */
242
	ulint	shift)	/* in: shift right applied after masking */
243
{
244
	ut_ad(rec);
245
	ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
246
	ut_ad(mask > 0xFFUL);
247
	ut_ad(mask <= 0xFFFFUL);
248
	ut_ad((mask >> shift) & 1);
249
	ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1)));
250
	ut_ad(((mask >> shift) << shift) == mask);
251
	ut_ad(((val << shift) & mask) == (val << shift));
252
253
	mach_write_to_2(rec - offs,
254
			(mach_read_from_2(rec - offs) & ~mask)
255
			| (val << shift));
256
}
257
258
/**********************************************************
259
The following function is used to get the offset of the next chained record
260
on the same page. */
261
UNIV_INLINE
262
ulint
263
rec_get_next_offs(
264
/*==============*/
265
			/* out: the page offset of the next chained record, or
266
			0 if none */
267
	rec_t*	rec,	/* in: physical record */
268
	ulint	comp)	/* in: nonzero=compact page format */
269
{
270
	ulint	field_value;
271
#if REC_NEXT_MASK != 0xFFFFUL
272
# error "REC_NEXT_MASK != 0xFFFFUL"
273
#endif
274
#if REC_NEXT_SHIFT
275
# error "REC_NEXT_SHIFT != 0"
276
#endif
277
278
	field_value = mach_read_from_2(rec - REC_NEXT);
279
280
	if (comp) {
281
#if UNIV_PAGE_SIZE <= 32768
282
		/* Note that for 64 KiB pages, field_value can 'wrap around'
283
		and the debug assertion is not valid */
284
285
		/* In the following assertion, field_value is interpreted
286
		as signed 16-bit integer in 2's complement arithmetics.
287
		If all platforms defined int16_t in the standard headers,
288
		the expression could be written simpler as
289
		(int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE
290
		*/
291
		ut_ad((field_value >= 32768
292
		       ? field_value - 65536
293
		       : field_value)
294
		      + ut_align_offset(rec, UNIV_PAGE_SIZE)
295
		      < UNIV_PAGE_SIZE);
296
#endif
297
		if (field_value == 0) {
298
299
			return(0);
300
		}
301
302
		return(ut_align_offset(rec + field_value, UNIV_PAGE_SIZE));
303
	} else {
304
		ut_ad(field_value < UNIV_PAGE_SIZE);
305
306
		return(field_value);
307
	}
308
}
309
310
/**********************************************************
311
The following function is used to set the next record offset field of the
312
record. */
313
UNIV_INLINE
314
void
315
rec_set_next_offs(
316
/*==============*/
317
	rec_t*	rec,	/* in: physical record */
318
	ulint	comp,	/* in: nonzero=compact page format */
319
	ulint	next)	/* in: offset of the next record, or 0 if none */
320
{
321
	ut_ad(rec);
322
	ut_ad(UNIV_PAGE_SIZE > next);
323
#if REC_NEXT_MASK != 0xFFFFUL
324
# error "REC_NEXT_MASK != 0xFFFFUL"
325
#endif
326
#if REC_NEXT_SHIFT
327
# error "REC_NEXT_SHIFT != 0"
328
#endif
329
330
	if (comp) {
331
		ulint field_value;
332
333
		if (next) {
334
			/* The following two statements calculate
335
			next - offset_of_rec mod 64Ki, where mod is the modulo
336
			as a non-negative number */
337
338
			field_value = (ulint)((lint)next
339
					      - (lint)ut_align_offset(
340
						      rec, UNIV_PAGE_SIZE));
341
			field_value &= REC_NEXT_MASK;
342
		} else {
343
			field_value = 0;
344
		}
345
346
		mach_write_to_2(rec - REC_NEXT, field_value);
347
	} else {
348
		mach_write_to_2(rec - REC_NEXT, next);
349
	}
350
}
351
352
/**********************************************************
353
The following function is used to get the number of fields
354
in an old-style record. */
355
UNIV_INLINE
356
ulint
357
rec_get_n_fields_old(
358
/*=================*/
359
			/* out: number of data fields */
360
	rec_t*	rec)	/* in: physical record */
361
{
362
	ulint	ret;
363
364
	ut_ad(rec);
365
366
	ret = rec_get_bit_field_2(rec, REC_OLD_N_FIELDS,
367
				  REC_OLD_N_FIELDS_MASK,
368
				  REC_OLD_N_FIELDS_SHIFT);
369
	ut_ad(ret <= REC_MAX_N_FIELDS);
370
	ut_ad(ret > 0);
371
372
	return(ret);
373
}
374
375
/**********************************************************
376
The following function is used to set the number of fields
377
in an old-style record. */
378
UNIV_INLINE
379
void
380
rec_set_n_fields_old(
381
/*=================*/
382
	rec_t*	rec,		/* in: physical record */
383
	ulint	n_fields)	/* in: the number of fields */
384
{
385
	ut_ad(rec);
386
	ut_ad(n_fields <= REC_MAX_N_FIELDS);
387
	ut_ad(n_fields > 0);
388
389
	rec_set_bit_field_2(rec, n_fields, REC_OLD_N_FIELDS,
390
			    REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);
391
}
392
393
/**********************************************************
394
The following function retrieves the status bits of a new-style record. */
395
UNIV_INLINE
396
ulint
397
rec_get_status(
398
/*===========*/
399
			/* out: status bits */
400
	rec_t*	rec)	/* in: physical record */
401
{
402
	ulint	ret;
403
404
	ut_ad(rec);
405
406
	ret = rec_get_bit_field_1(rec, REC_NEW_STATUS,
407
				  REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
408
	ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0);
409
410
	return(ret);
411
}
412
413
/**********************************************************
414
The following function is used to get the number of fields
415
in a record. */
416
UNIV_INLINE
417
ulint
418
rec_get_n_fields(
419
/*=============*/
420
				/* out: number of data fields */
421
	rec_t*		rec,	/* in: physical record */
422
	dict_index_t*	index)	/* in: record descriptor */
423
{
424
	ut_ad(rec);
425
	ut_ad(index);
426
427
	if (!dict_table_is_comp(index->table)) {
428
		return(rec_get_n_fields_old(rec));
429
	}
430
431
	switch (rec_get_status(rec)) {
432
	case REC_STATUS_ORDINARY:
433
		return(dict_index_get_n_fields(index));
434
	case REC_STATUS_NODE_PTR:
435
		return(dict_index_get_n_unique_in_tree(index) + 1);
436
	case REC_STATUS_INFIMUM:
437
	case REC_STATUS_SUPREMUM:
438
		return(1);
439
	default:
440
		ut_error;
441
		return(ULINT_UNDEFINED);
442
	}
443
}
444
445
/**********************************************************
446
The following function is used to get the number of records owned by the
447
previous directory record. */
448
UNIV_INLINE
449
ulint
450
rec_get_n_owned(
451
/*============*/
452
			/* out: number of owned records */
453
	rec_t*	rec,	/* in: physical record */
454
	ulint	comp)	/* in: nonzero=compact page format */
455
{
456
	ulint	ret;
457
458
	ut_ad(rec);
459
460
	ret = rec_get_bit_field_1(rec,
461
				  comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
462
				  REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
463
	ut_ad(ret <= REC_MAX_N_OWNED);
464
465
	return(ret);
466
}
467
468
/**********************************************************
469
The following function is used to set the number of owned records. */
470
UNIV_INLINE
471
void
472
rec_set_n_owned(
473
/*============*/
474
	rec_t*	rec,		/* in: physical record */
475
	ulint	comp,		/* in: nonzero=compact page format */
476
	ulint	n_owned)	/* in: the number of owned */
477
{
478
	ut_ad(rec);
479
	ut_ad(n_owned <= REC_MAX_N_OWNED);
480
481
	rec_set_bit_field_1(rec, n_owned,
482
			    comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
483
			    REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
484
}
485
486
/**********************************************************
487
The following function is used to retrieve the info bits of a record. */
488
UNIV_INLINE
489
ulint
490
rec_get_info_bits(
491
/*==============*/
492
			/* out: info bits */
493
	rec_t*	rec,	/* in: physical record */
494
	ulint	comp)	/* in: nonzero=compact page format */
495
{
496
	ulint	ret;
497
498
	ut_ad(rec);
499
500
	ret = rec_get_bit_field_1(rec,
501
				  comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
502
				  REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
503
	ut_ad((ret & ~REC_INFO_BITS_MASK) == 0);
504
505
	return(ret);
506
}
507
508
/**********************************************************
509
The following function is used to set the info bits of a record. */
510
UNIV_INLINE
511
void
512
rec_set_info_bits(
513
/*==============*/
514
	rec_t*	rec,	/* in: physical record */
515
	ulint	comp,	/* in: nonzero=compact page format */
516
	ulint	bits)	/* in: info bits */
517
{
518
	ut_ad(rec);
519
	ut_ad((bits & ~REC_INFO_BITS_MASK) == 0);
520
521
	rec_set_bit_field_1(rec, bits,
522
			    comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
523
			    REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
524
}
525
526
/**********************************************************
527
The following function is used to set the status bits of a new-style record. */
528
UNIV_INLINE
529
void
530
rec_set_status(
531
/*===========*/
532
	rec_t*	rec,	/* in: physical record */
533
	ulint	bits)	/* in: info bits */
534
{
535
	ut_ad(rec);
536
	ut_ad((bits & ~REC_NEW_STATUS_MASK) == 0);
537
538
	rec_set_bit_field_1(rec, bits, REC_NEW_STATUS,
539
			    REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
540
}
541
542
/**********************************************************
543
The following function is used to retrieve the info and status
544
bits of a record.  (Only compact records have status bits.) */
545
UNIV_INLINE
546
ulint
547
rec_get_info_and_status_bits(
548
/*=========================*/
549
			/* out: info bits */
550
	rec_t*	rec,	/* in: physical record */
551
	ulint	comp)	/* in: nonzero=compact page format */
552
{
553
	ulint	bits;
554
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
555
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
556
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
557
#endif
558
	if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
559
		bits = rec_get_info_bits(rec, TRUE) | rec_get_status(rec);
560
	} else {
561
		bits = rec_get_info_bits(rec, FALSE);
562
		ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
563
	}
564
	return(bits);
565
}
566
/**********************************************************
567
The following function is used to set the info and status
568
bits of a record.  (Only compact records have status bits.) */
569
UNIV_INLINE
570
void
571
rec_set_info_and_status_bits(
572
/*=========================*/
573
	rec_t*	rec,	/* in: physical record */
574
	ulint	comp,	/* in: nonzero=compact page format */
575
	ulint	bits)	/* in: info bits */
576
{
577
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
578
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
579
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
580
#endif
581
	if (comp) {
582
		rec_set_status(rec, bits & REC_NEW_STATUS_MASK);
583
	} else {
584
		ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
585
	}
586
	rec_set_info_bits(rec, comp, bits & ~REC_NEW_STATUS_MASK);
587
}
588
589
/**********************************************************
590
The following function tells if record is delete marked. */
591
UNIV_INLINE
592
ulint
593
rec_get_deleted_flag(
594
/*=================*/
595
			/* out: nonzero if delete marked */
596
	rec_t*	rec,	/* in: physical record */
597
	ulint	comp)	/* in: nonzero=compact page format */
598
{
599
	if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
600
		return(UNIV_UNLIKELY(
601
			       rec_get_bit_field_1(rec, REC_NEW_INFO_BITS,
602
						   REC_INFO_DELETED_FLAG,
603
						   REC_INFO_BITS_SHIFT)));
604
	} else {
605
		return(UNIV_UNLIKELY(
606
			       rec_get_bit_field_1(rec, REC_OLD_INFO_BITS,
607
						   REC_INFO_DELETED_FLAG,
608
						   REC_INFO_BITS_SHIFT)));
609
	}
610
}
611
612
/**********************************************************
613
The following function is used to set the deleted bit. */
614
UNIV_INLINE
615
void
616
rec_set_deleted_flag(
617
/*=================*/
618
	rec_t*	rec,	/* in: physical record */
619
	ulint	comp,	/* in: nonzero=compact page format */
620
	ulint	flag)	/* in: nonzero if delete marked */
621
{
622
	ulint	val;
623
624
	val = rec_get_info_bits(rec, comp);
625
626
	if (flag) {
627
		val |= REC_INFO_DELETED_FLAG;
628
	} else {
629
		val &= ~REC_INFO_DELETED_FLAG;
630
	}
631
632
	rec_set_info_bits(rec, comp, val);
633
}
634
635
/**********************************************************
636
The following function tells if a new-style record is a node pointer. */
637
UNIV_INLINE
638
ibool
639
rec_get_node_ptr_flag(
640
/*==================*/
641
			/* out: TRUE if node pointer */
642
	rec_t*	rec)	/* in: physical record */
643
{
644
	return(REC_STATUS_NODE_PTR == rec_get_status(rec));
645
}
646
647
/**********************************************************
648
The following function is used to get the order number of the record in the
649
heap of the index page. */
650
UNIV_INLINE
651
ulint
652
rec_get_heap_no(
653
/*============*/
654
			/* out: heap order number */
655
	rec_t*	rec,	/* in: physical record */
656
	ulint	comp)	/* in: nonzero=compact page format */
657
{
658
	ulint	ret;
659
660
	ut_ad(rec);
661
662
	ret = rec_get_bit_field_2(rec,
663
				  comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
664
				  REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
665
	ut_ad(ret <= REC_MAX_HEAP_NO);
666
667
	return(ret);
668
}
669
670
/**********************************************************
671
The following function is used to set the heap number field in the record. */
672
UNIV_INLINE
673
void
674
rec_set_heap_no(
675
/*============*/
676
	rec_t*	rec,	/* in: physical record */
677
	ulint	comp,	/* in: nonzero=compact page format */
678
	ulint	heap_no)/* in: the heap number */
679
{
680
	ut_ad(heap_no <= REC_MAX_HEAP_NO);
681
682
	rec_set_bit_field_2(rec, heap_no,
683
			    comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
684
			    REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
685
}
686
687
/**********************************************************
688
The following function is used to test whether the data offsets in the record
689
are stored in one-byte or two-byte format. */
690
UNIV_INLINE
691
ibool
692
rec_get_1byte_offs_flag(
693
/*====================*/
694
			/* out: TRUE if 1-byte form */
695
	rec_t*	rec)	/* in: physical record */
696
{
697
#if TRUE != 1
698
#error "TRUE != 1"
699
#endif
700
701
	return(rec_get_bit_field_1(rec, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
702
				   REC_OLD_SHORT_SHIFT));
703
}
704
705
/**********************************************************
706
The following function is used to set the 1-byte offsets flag. */
707
UNIV_INLINE
708
void
709
rec_set_1byte_offs_flag(
710
/*====================*/
711
	rec_t*	rec,	/* in: physical record */
712
	ibool	flag)	/* in: TRUE if 1byte form */
713
{
714
#if TRUE != 1
715
#error "TRUE != 1"
716
#endif
717
	ut_ad(flag <= TRUE);
718
719
	rec_set_bit_field_1(rec, flag, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
720
			    REC_OLD_SHORT_SHIFT);
721
}
722
723
/**********************************************************
724
Returns the offset of nth field end if the record is stored in the 1-byte
725
offsets form. If the field is SQL null, the flag is ORed in the returned
726
value. */
727
UNIV_INLINE
728
ulint
729
rec_1_get_field_end_info(
730
/*=====================*/
731
			/* out: offset of the start of the field, SQL null
732
			flag ORed */
733
	rec_t*	rec,	/* in: record */
734
	ulint	n)	/* in: field index */
735
{
736
	ut_ad(rec_get_1byte_offs_flag(rec));
737
	ut_ad(n < rec_get_n_fields_old(rec));
738
739
	return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1)));
740
}
741
742
/**********************************************************
743
Returns the offset of nth field end if the record is stored in the 2-byte
744
offsets form. If the field is SQL null, the flag is ORed in the returned
745
value. */
746
UNIV_INLINE
747
ulint
748
rec_2_get_field_end_info(
749
/*=====================*/
750
			/* out: offset of the start of the field, SQL null
751
			flag and extern storage flag ORed */
752
	rec_t*	rec,	/* in: record */
753
	ulint	n)	/* in: field index */
754
{
755
	ut_ad(!rec_get_1byte_offs_flag(rec));
756
	ut_ad(n < rec_get_n_fields_old(rec));
757
758
	return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2)));
759
}
760
761
#ifdef UNIV_DEBUG
762
/* Length of the rec_get_offsets() header */
763
# define REC_OFFS_HEADER_SIZE	4
764
#else /* UNIV_DEBUG */
765
/* Length of the rec_get_offsets() header */
766
# define REC_OFFS_HEADER_SIZE	2
767
#endif /* UNIV_DEBUG */
768
769
/* Get the base address of offsets.  The extra_size is stored at
770
this position, and following positions hold the end offsets of
771
the fields. */
772
#define rec_offs_base(offsets) (offsets + REC_OFFS_HEADER_SIZE)
773
774
/**************************************************************
775
The following function returns the number of allocated elements
776
for an array of offsets. */
777
UNIV_INLINE
778
ulint
779
rec_offs_get_n_alloc(
780
/*=================*/
781
				/* out: number of elements */
782
	const ulint*	offsets)/* in: array for rec_get_offsets() */
783
{
784
	ulint	n_alloc;
785
	ut_ad(offsets);
786
	n_alloc = offsets[0];
787
	ut_ad(n_alloc > 0);
788
	return(n_alloc);
789
}
790
791
/**************************************************************
792
The following function sets the number of allocated elements
793
for an array of offsets. */
794
UNIV_INLINE
795
void
796
rec_offs_set_n_alloc(
797
/*=================*/
798
	ulint*	offsets,	/* out: array for rec_get_offsets(),
799
				must be allocated */
800
	ulint	n_alloc)	/* in: number of elements */
801
{
802
	ut_ad(offsets);
803
	ut_ad(n_alloc > 0);
804
	UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets);
805
	offsets[0] = n_alloc;
806
}
807
808
/**************************************************************
809
The following function returns the number of fields in a record. */
810
UNIV_INLINE
811
ulint
812
rec_offs_n_fields(
813
/*==============*/
814
				/* out: number of fields */
815
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
816
{
817
	ulint	n_fields;
818
	ut_ad(offsets);
819
	n_fields = offsets[1];
820
	ut_ad(n_fields > 0);
821
	ut_ad(n_fields <= REC_MAX_N_FIELDS);
822
	ut_ad(n_fields + REC_OFFS_HEADER_SIZE
823
	      <= rec_offs_get_n_alloc(offsets));
824
	return(n_fields);
825
}
826
827
/****************************************************************
828
Validates offsets returned by rec_get_offsets(). */
829
UNIV_INLINE
830
ibool
831
rec_offs_validate(
832
/*==============*/
833
				/* out: TRUE if valid */
834
	rec_t*		rec,	/* in: record or NULL */
835
	dict_index_t*	index,	/* in: record descriptor or NULL */
836
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
837
{
838
	ulint	i	= rec_offs_n_fields(offsets);
839
	ulint	last	= ULINT_MAX;
840
	ulint	comp	= *rec_offs_base(offsets) & REC_OFFS_COMPACT;
841
842
	if (rec) {
843
		ut_ad((ulint) rec == offsets[2]);
844
		if (!comp) {
845
			ut_a(rec_get_n_fields_old(rec) >= i);
846
		}
847
	}
848
	if (index) {
849
		ulint max_n_fields;
850
		ut_ad((ulint) index == offsets[3]);
851
		max_n_fields = ut_max(
852
			dict_index_get_n_fields(index),
853
			dict_index_get_n_unique_in_tree(index) + 1);
854
		if (comp && rec) {
855
			switch (rec_get_status(rec)) {
856
			case REC_STATUS_ORDINARY:
857
				break;
858
			case REC_STATUS_NODE_PTR:
859
				max_n_fields = dict_index_get_n_unique_in_tree(
860
					index) + 1;
861
				break;
862
			case REC_STATUS_INFIMUM:
863
			case REC_STATUS_SUPREMUM:
864
				max_n_fields = 1;
865
				break;
866
			default:
867
				ut_error;
868
			}
869
		}
870
		/* index->n_def == 0 for dummy indexes if !comp */
871
		ut_a(!comp || index->n_def);
872
		ut_a(!index->n_def || i <= max_n_fields);
873
	}
874
	while (i--) {
875
		ulint	curr = rec_offs_base(offsets)[1 + i] & REC_OFFS_MASK;
876
		ut_a(curr <= last);
877
		last = curr;
878
	}
879
	return(TRUE);
880
}
881
/****************************************************************
882
Updates debug data in offsets, in order to avoid bogus
883
rec_offs_validate() failures. */
884
UNIV_INLINE
885
void
886
rec_offs_make_valid(
887
/*================*/
888
	rec_t*		rec __attribute__((unused)),
889
				/* in: record */
890
	dict_index_t*	index __attribute__((unused)),
891
				/* in: record descriptor */
892
	ulint*		offsets __attribute__((unused)))
893
				/* in: array returned by rec_get_offsets() */
894
{
895
#ifdef UNIV_DEBUG
896
	ut_ad(rec_get_n_fields(rec, index) >= rec_offs_n_fields(offsets));
897
	offsets[2] = (ulint) rec;
898
	offsets[3] = (ulint) index;
899
#endif /* UNIV_DEBUG */
900
}
901
902
/****************************************************************
903
The following function is used to get a pointer to the nth
904
data field in a record. */
905
UNIV_INLINE
906
byte*
907
rec_get_nth_field(
908
/*==============*/
909
				/* out: pointer to the field */
910
	rec_t*		rec,	/* in: record */
911
	const ulint*	offsets,/* in: array returned by rec_get_offsets() */
912
	ulint		n,	/* in: index of the field */
913
	ulint*		len)	/* out: length of the field; UNIV_SQL_NULL
914
				if SQL null */
915
{
916
	byte*	field;
917
	ulint	length;
918
	ut_ad(rec);
919
	ut_ad(rec_offs_validate(rec, NULL, offsets));
920
	ut_ad(n < rec_offs_n_fields(offsets));
921
	ut_ad(len);
922
923
	if (UNIV_UNLIKELY(n == 0)) {
924
		field = rec;
925
	} else {
926
		field = rec + (rec_offs_base(offsets)[n] & REC_OFFS_MASK);
927
	}
928
929
	length = rec_offs_base(offsets)[1 + n];
930
931
	if (length & REC_OFFS_SQL_NULL) {
932
		length = UNIV_SQL_NULL;
933
	} else {
934
		length &= REC_OFFS_MASK;
935
		length -= field - rec;
936
	}
937
938
	*len = length;
939
	return(field);
940
}
941
942
/**********************************************************
943
Determine if the offsets are for a record in the new
944
compact format. */
945
UNIV_INLINE
946
ulint
947
rec_offs_comp(
948
/*==========*/
949
				/* out: nonzero if compact format */
950
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
951
{
952
	ut_ad(rec_offs_validate(NULL, NULL, offsets));
953
	return(*rec_offs_base(offsets) & REC_OFFS_COMPACT);
954
}
955
956
/**********************************************************
957
Returns nonzero if the extern bit is set in nth field of rec. */
958
UNIV_INLINE
959
ulint
960
rec_offs_nth_extern(
961
/*================*/
962
				/* out: nonzero if externally stored */
963
	const ulint*	offsets,/* in: array returned by rec_get_offsets() */
964
	ulint		n)	/* in: nth field */
965
{
966
	ut_ad(rec_offs_validate(NULL, NULL, offsets));
967
	ut_ad(n < rec_offs_n_fields(offsets));
968
	return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
969
			     & REC_OFFS_EXTERNAL));
970
}
971
972
/**********************************************************
973
Returns nonzero if the SQL NULL bit is set in nth field of rec. */
974
UNIV_INLINE
975
ulint
976
rec_offs_nth_sql_null(
977
/*==================*/
978
				/* out: nonzero if SQL NULL */
979
	const ulint*	offsets,/* in: array returned by rec_get_offsets() */
980
	ulint		n)	/* in: nth field */
981
{
982
	ut_ad(rec_offs_validate(NULL, NULL, offsets));
983
	ut_ad(n < rec_offs_n_fields(offsets));
984
	return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
985
			     & REC_OFFS_SQL_NULL));
986
}
987
988
/**********************************************************
989
Gets the physical size of a field. */
990
UNIV_INLINE
991
ulint
992
rec_offs_nth_size(
993
/*==============*/
994
				/* out: length of field */
995
	const ulint*	offsets,/* in: array returned by rec_get_offsets() */
996
	ulint		n)	/* in: nth field */
997
{
998
	ut_ad(rec_offs_validate(NULL, NULL, offsets));
999
	ut_ad(n < rec_offs_n_fields(offsets));
1000
	if (!n) {
1001
		return(rec_offs_base(offsets)[1 + n] & REC_OFFS_MASK);
1002
	}
1003
	return((rec_offs_base(offsets)[1 + n] - rec_offs_base(offsets)[n])
1004
	       & REC_OFFS_MASK);
1005
}
1006
1007
/**********************************************************
1008
Returns TRUE if the extern bit is set in any of the fields
1009
of an old-style record. */
1010
UNIV_INLINE
1011
ibool
1012
rec_offs_any_extern(
1013
/*================*/
1014
				/* out: TRUE if a field is stored externally */
1015
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
1016
{
1017
	ulint	i;
1018
	for (i = rec_offs_n_fields(offsets); i--; ) {
1019
		if (rec_offs_nth_extern(offsets, i)) {
1020
			return(TRUE);
1021
		}
1022
	}
1023
	return(FALSE);
1024
}
1025
1026
/***************************************************************
1027
Sets the value of the ith field extern storage bit. */
1028
UNIV_INLINE
1029
void
1030
rec_set_nth_field_extern_bit(
1031
/*=========================*/
1032
	rec_t*		rec,	/* in: record */
1033
	dict_index_t*	index,	/* in: record descriptor */
1034
	ulint		i,	/* in: ith field */
1035
	ibool		val,	/* in: value to set */
1036
	mtr_t*		mtr)	/* in: mtr holding an X-latch to the page
1037
				where rec is, or NULL; in the NULL case
1038
				we do not write to log about the change */
1039
{
1040
	if (dict_table_is_comp(index->table)) {
1041
		rec_set_nth_field_extern_bit_new(rec, index, i, val, mtr);
1042
	} else {
1043
		rec_set_nth_field_extern_bit_old(rec, i, val, mtr);
1044
	}
1045
}
1046
1047
/**********************************************************
1048
Returns the offset of n - 1th field end if the record is stored in the 1-byte
1049
offsets form. If the field is SQL null, the flag is ORed in the returned
1050
value. This function and the 2-byte counterpart are defined here because the
1051
C-compiler was not able to sum negative and positive constant offsets, and
1052
warned of constant arithmetic overflow within the compiler. */
1053
UNIV_INLINE
1054
ulint
1055
rec_1_get_prev_field_end_info(
1056
/*==========================*/
1057
			/* out: offset of the start of the PREVIOUS field, SQL
1058
			null flag ORed */
1059
	rec_t*	rec,	/* in: record */
1060
	ulint	n)	/* in: field index */
1061
{
1062
	ut_ad(rec_get_1byte_offs_flag(rec));
1063
	ut_ad(n <= rec_get_n_fields_old(rec));
1064
1065
	return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n)));
1066
}
1067
1068
/**********************************************************
1069
Returns the offset of n - 1th field end if the record is stored in the 2-byte
1070
offsets form. If the field is SQL null, the flag is ORed in the returned
1071
value. */
1072
UNIV_INLINE
1073
ulint
1074
rec_2_get_prev_field_end_info(
1075
/*==========================*/
1076
			/* out: offset of the start of the PREVIOUS field, SQL
1077
			null flag ORed */
1078
	rec_t*	rec,	/* in: record */
1079
	ulint	n)	/* in: field index */
1080
{
1081
	ut_ad(!rec_get_1byte_offs_flag(rec));
1082
	ut_ad(n <= rec_get_n_fields_old(rec));
1083
1084
	return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n)));
1085
}
1086
1087
/**********************************************************
1088
Sets the field end info for the nth field if the record is stored in the
1089
1-byte format. */
1090
UNIV_INLINE
1091
void
1092
rec_1_set_field_end_info(
1093
/*=====================*/
1094
	rec_t*	rec,	/* in: record */
1095
	ulint	n,	/* in: field index */
1096
	ulint	info)	/* in: value to set */
1097
{
1098
	ut_ad(rec_get_1byte_offs_flag(rec));
1099
	ut_ad(n < rec_get_n_fields_old(rec));
1100
1101
	mach_write_to_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1), info);
1102
}
1103
1104
/**********************************************************
1105
Sets the field end info for the nth field if the record is stored in the
1106
2-byte format. */
1107
UNIV_INLINE
1108
void
1109
rec_2_set_field_end_info(
1110
/*=====================*/
1111
	rec_t*	rec,	/* in: record */
1112
	ulint	n,	/* in: field index */
1113
	ulint	info)	/* in: value to set */
1114
{
1115
	ut_ad(!rec_get_1byte_offs_flag(rec));
1116
	ut_ad(n < rec_get_n_fields_old(rec));
1117
1118
	mach_write_to_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2), info);
1119
}
1120
1121
/**********************************************************
1122
Returns the offset of nth field start if the record is stored in the 1-byte
1123
offsets form. */
1124
UNIV_INLINE
1125
ulint
1126
rec_1_get_field_start_offs(
1127
/*=======================*/
1128
			/* out: offset of the start of the field */
1129
	rec_t*	rec,	/* in: record */
1130
	ulint	n)	/* in: field index */
1131
{
1132
	ut_ad(rec_get_1byte_offs_flag(rec));
1133
	ut_ad(n <= rec_get_n_fields_old(rec));
1134
1135
	if (n == 0) {
1136
1137
		return(0);
1138
	}
1139
1140
	return(rec_1_get_prev_field_end_info(rec, n)
1141
	       & ~REC_1BYTE_SQL_NULL_MASK);
1142
}
1143
1144
/**********************************************************
1145
Returns the offset of nth field start if the record is stored in the 2-byte
1146
offsets form. */
1147
UNIV_INLINE
1148
ulint
1149
rec_2_get_field_start_offs(
1150
/*=======================*/
1151
			/* out: offset of the start of the field */
1152
	rec_t*	rec,	/* in: record */
1153
	ulint	n)	/* in: field index */
1154
{
1155
	ut_ad(!rec_get_1byte_offs_flag(rec));
1156
	ut_ad(n <= rec_get_n_fields_old(rec));
1157
1158
	if (n == 0) {
1159
1160
		return(0);
1161
	}
1162
1163
	return(rec_2_get_prev_field_end_info(rec, n)
1164
	       & ~(REC_2BYTE_SQL_NULL_MASK | REC_2BYTE_EXTERN_MASK));
1165
}
1166
1167
/**********************************************************
1168
The following function is used to read the offset of the start of a data field
1169
in the record. The start of an SQL null field is the end offset of the
1170
previous non-null field, or 0, if none exists. If n is the number of the last
1171
field + 1, then the end offset of the last field is returned. */
1172
UNIV_INLINE
1173
ulint
1174
rec_get_field_start_offs(
1175
/*=====================*/
1176
			/* out: offset of the start of the field */
1177
	rec_t*	rec,	/* in: record */
1178
	ulint	n)	/* in: field index */
1179
{
1180
	ut_ad(rec);
1181
	ut_ad(n <= rec_get_n_fields_old(rec));
1182
1183
	if (n == 0) {
1184
1185
		return(0);
1186
	}
1187
1188
	if (rec_get_1byte_offs_flag(rec)) {
1189
1190
		return(rec_1_get_field_start_offs(rec, n));
1191
	}
1192
1193
	return(rec_2_get_field_start_offs(rec, n));
1194
}
1195
1196
/****************************************************************
1197
Gets the physical size of an old-style field.
1198
Also an SQL null may have a field of size > 0,
1199
if the data type is of a fixed size. */
1200
UNIV_INLINE
1201
ulint
1202
rec_get_nth_field_size(
1203
/*===================*/
1204
			/* out: field size in bytes */
1205
	rec_t*	rec,	/* in: record */
1206
	ulint	n)	/* in: index of the field */
1207
{
1208
	ulint	os;
1209
	ulint	next_os;
1210
1211
	os = rec_get_field_start_offs(rec, n);
1212
	next_os = rec_get_field_start_offs(rec, n + 1);
1213
1214
	ut_ad(next_os - os < UNIV_PAGE_SIZE);
1215
1216
	return(next_os - os);
1217
}
1218
1219
/***************************************************************
1220
This is used to modify the value of an already existing field in a record.
1221
The previous value must have exactly the same size as the new value. If len
1222
is UNIV_SQL_NULL then the field is treated as an SQL null for old-style
1223
records. For new-style records, len must not be UNIV_SQL_NULL. */
1224
UNIV_INLINE
1225
void
1226
rec_set_nth_field(
1227
/*==============*/
1228
	rec_t*		rec,	/* in: record */
1229
	const ulint*	offsets,/* in: array returned by rec_get_offsets() */
1230
	ulint		n,	/* in: index number of the field */
1231
	const void*	data,	/* in: pointer to the data
1232
				if not SQL null */
1233
	ulint		len)	/* in: length of the data or UNIV_SQL_NULL.
1234
				If not SQL null, must have the same
1235
				length as the previous value.
1236
				If SQL null, previous value must be
1237
				SQL null. */
1238
{
1239
	byte*	data2;
1240
	ulint	len2;
1241
1242
	ut_ad(rec);
1243
	ut_ad(rec_offs_validate(rec, NULL, offsets));
1244
1245
	if (len == UNIV_SQL_NULL) {
1246
		ut_ad(!rec_offs_comp(offsets));
1247
		rec_set_nth_field_sql_null(rec, n);
1248
1249
		return;
1250
	}
1251
1252
	data2 = rec_get_nth_field(rec, offsets, n, &len2);
1253
	if (len2 == UNIV_SQL_NULL) {
1254
		ut_ad(!rec_offs_comp(offsets));
1255
		rec_set_nth_field_null_bit(rec, n, FALSE);
1256
		ut_ad(len == rec_get_nth_field_size(rec, n));
1257
	} else {
1258
		ut_ad(len2 == len);
1259
	}
1260
1261
	ut_memcpy(data2, data, len);
1262
}
1263
1264
/**************************************************************
1265
The following function returns the data size of an old-style physical
1266
record, that is the sum of field lengths. SQL null fields
1267
are counted as length 0 fields. The value returned by the function
1268
is the distance from record origin to record end in bytes. */
1269
UNIV_INLINE
1270
ulint
1271
rec_get_data_size_old(
1272
/*==================*/
1273
				/* out: size */
1274
	rec_t*	rec)	/* in: physical record */
1275
{
1276
	ut_ad(rec);
1277
1278
	return(rec_get_field_start_offs(rec, rec_get_n_fields_old(rec)));
1279
}
1280
1281
/**************************************************************
1282
The following function sets the number of fields in offsets. */
1283
UNIV_INLINE
1284
void
1285
rec_offs_set_n_fields(
1286
/*==================*/
1287
	ulint*	offsets,	/* in/out: array returned by
1288
				rec_get_offsets() */
1289
	ulint	n_fields)	/* in: number of fields */
1290
{
1291
	ut_ad(offsets);
1292
	ut_ad(n_fields > 0);
1293
	ut_ad(n_fields <= REC_MAX_N_FIELDS);
1294
	ut_ad(n_fields + REC_OFFS_HEADER_SIZE
1295
	      <= rec_offs_get_n_alloc(offsets));
1296
	offsets[1] = n_fields;
1297
}
1298
1299
/**************************************************************
1300
The following function returns the data size of a physical
1301
record, that is the sum of field lengths. SQL null fields
1302
are counted as length 0 fields. The value returned by the function
1303
is the distance from record origin to record end in bytes. */
1304
UNIV_INLINE
1305
ulint
1306
rec_offs_data_size(
1307
/*===============*/
1308
				/* out: size */
1309
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
1310
{
1311
	ulint	size;
1312
1313
	ut_ad(rec_offs_validate(NULL, NULL, offsets));
1314
	size = rec_offs_base(offsets)[rec_offs_n_fields(offsets)]
1315
		& REC_OFFS_MASK;
1316
	ut_ad(size < UNIV_PAGE_SIZE);
1317
	return(size);
1318
}
1319
1320
/**************************************************************
1321
Returns the total size of record minus data size of record. The value
1322
returned by the function is the distance from record start to record origin
1323
in bytes. */
1324
UNIV_INLINE
1325
ulint
1326
rec_offs_extra_size(
1327
/*================*/
1328
				/* out: size */
1329
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
1330
{
1331
	ulint	size;
1332
	ut_ad(rec_offs_validate(NULL, NULL, offsets));
1333
	size = *rec_offs_base(offsets) & ~REC_OFFS_COMPACT;
1334
	ut_ad(size < UNIV_PAGE_SIZE);
1335
	return(size);
1336
}
1337
1338
/**************************************************************
1339
Returns the total size of a physical record.  */
1340
UNIV_INLINE
1341
ulint
1342
rec_offs_size(
1343
/*==========*/
1344
				/* out: size */
1345
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
1346
{
1347
	return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets));
1348
}
1349
1350
/**************************************************************
1351
Returns a pointer to the end of the record. */
1352
UNIV_INLINE
1353
byte*
1354
rec_get_end(
1355
/*========*/
1356
				/* out: pointer to end */
1357
	rec_t*		rec,	/* in: pointer to record */
1358
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
1359
{
1360
	return(rec + rec_offs_data_size(offsets));
1361
}
1362
1363
/**************************************************************
1364
Returns a pointer to the start of the record. */
1365
UNIV_INLINE
1366
byte*
1367
rec_get_start(
1368
/*==========*/
1369
				/* out: pointer to start */
1370
	rec_t*		rec,	/* in: pointer to record */
1371
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
1372
{
1373
	return(rec - rec_offs_extra_size(offsets));
1374
}
1375
1376
/*******************************************************************
1377
Copies a physical record to a buffer. */
1378
UNIV_INLINE
1379
rec_t*
1380
rec_copy(
1381
/*=====*/
1382
				/* out: pointer to the origin of the copy */
1383
	void*		buf,	/* in: buffer */
1384
	const rec_t*	rec,	/* in: physical record */
1385
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
1386
{
1387
	ulint	extra_len;
1388
	ulint	data_len;
1389
1390
	ut_ad(rec && buf);
1391
	ut_ad(rec_offs_validate((rec_t*) rec, NULL, offsets));
1392
	ut_ad(rec_validate((rec_t*) rec, offsets));
1393
1394
	extra_len = rec_offs_extra_size(offsets);
1395
	data_len = rec_offs_data_size(offsets);
1396
1397
	ut_memcpy(buf, rec - extra_len, extra_len + data_len);
1398
1399
	return((byte*)buf + extra_len);
1400
}
1401
1402
/**************************************************************
1403
Returns the extra size of an old-style physical record if we know its
1404
data size and number of fields. */
1405
UNIV_INLINE
1406
ulint
1407
rec_get_converted_extra_size(
1408
/*=========================*/
1409
				/* out: extra size */
1410
	ulint	data_size,	/* in: data size */
1411
	ulint	n_fields)	/* in: number of fields */
1412
{
1413
	if (data_size <= REC_1BYTE_OFFS_LIMIT) {
1414
1415
		return(REC_N_OLD_EXTRA_BYTES + n_fields);
1416
	}
1417
1418
	return(REC_N_OLD_EXTRA_BYTES + 2 * n_fields);
1419
}
1420
1421
/**************************************************************
1422
The following function returns the size of a data tuple when converted to
1423
a new-style physical record. */
1424
1425
ulint
1426
rec_get_converted_size_new(
1427
/*=======================*/
1428
				/* out: size */
1429
	dict_index_t*	index,	/* in: record descriptor */
1430
	dtuple_t*	dtuple);/* in: data tuple */
1431
/**************************************************************
1432
The following function returns the size of a data tuple when converted to
1433
a physical record. */
1434
UNIV_INLINE
1435
ulint
1436
rec_get_converted_size(
1437
/*===================*/
1438
				/* out: size */
1439
	dict_index_t*	index,	/* in: record descriptor */
1440
	dtuple_t*	dtuple)	/* in: data tuple */
1441
{
1442
	ulint	data_size;
1443
	ulint	extra_size;
1444
1445
	ut_ad(index);
1446
	ut_ad(dtuple);
1447
	ut_ad(dtuple_check_typed(dtuple));
1448
1449
	ut_ad(index->type & DICT_UNIVERSAL
1450
	      || dtuple_get_n_fields(dtuple)
1451
	      == (((dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK)
1452
		   == REC_STATUS_NODE_PTR)
1453
		  ? dict_index_get_n_unique_in_tree(index) + 1
1454
		  : dict_index_get_n_fields(index)));
1455
1456
	if (dict_table_is_comp(index->table)) {
1457
		return(rec_get_converted_size_new(index, dtuple));
1458
	}
1459
1460
	data_size = dtuple_get_data_size(dtuple);
1461
1462
	extra_size = rec_get_converted_extra_size(
1463
		data_size, dtuple_get_n_fields(dtuple));
1464
1465
	return(data_size + extra_size);
1466
}
1467
1468
/****************************************************************
1469
Folds a prefix of a physical record to a ulint. Folds only existing fields,
1470
that is, checks that we do not run out of the record. */
1471
UNIV_INLINE
1472
ulint
1473
rec_fold(
1474
/*=====*/
1475
					/* out: the folded value */
1476
	rec_t*		rec,		/* in: the physical record */
1477
	const ulint*	offsets,	/* in: array returned by
1478
					rec_get_offsets() */
1479
	ulint		n_fields,	/* in: number of complete
1480
					fields to fold */
1481
	ulint		n_bytes,	/* in: number of bytes to fold
1482
					in an incomplete last field */
1483
	dulint		tree_id)	/* in: index tree id */
1484
{
1485
	ulint	i;
1486
	byte*	data;
1487
	ulint	len;
1488
	ulint	fold;
1489
	ulint	n_fields_rec;
1490
1491
	ut_ad(rec_offs_validate(rec, NULL, offsets));
1492
	ut_ad(rec_validate((rec_t*) rec, offsets));
1493
	ut_ad(n_fields + n_bytes > 0);
1494
1495
	n_fields_rec = rec_offs_n_fields(offsets);
1496
	ut_ad(n_fields <= n_fields_rec);
1497
	ut_ad(n_fields < n_fields_rec || n_bytes == 0);
1498
1499
	if (n_fields > n_fields_rec) {
1500
		n_fields = n_fields_rec;
1501
	}
1502
1503
	if (n_fields == n_fields_rec) {
1504
		n_bytes = 0;
1505
	}
1506
1507
	fold = ut_fold_dulint(tree_id);
1508
1509
	for (i = 0; i < n_fields; i++) {
1510
		data = rec_get_nth_field(rec, offsets, i, &len);
1511
1512
		if (len != UNIV_SQL_NULL) {
1513
			fold = ut_fold_ulint_pair(fold,
1514
						  ut_fold_binary(data, len));
1515
		}
1516
	}
1517
1518
	if (n_bytes > 0) {
1519
		data = rec_get_nth_field(rec, offsets, i, &len);
1520
1521
		if (len != UNIV_SQL_NULL) {
1522
			if (len > n_bytes) {
1523
				len = n_bytes;
1524
			}
1525
1526
			fold = ut_fold_ulint_pair(fold,
1527
						  ut_fold_binary(data, len));
1528
		}
1529
	}
1530
1531
	return(fold);
1532
}