~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/******************************************************
2
General row routines
3
4
(c) 1996 Innobase Oy
5
6
Created 4/20/1996 Heikki Tuuri
7
*******************************************************/
8
9
#include "row0row.h"
10
11
#ifdef UNIV_NONINL
12
#include "row0row.ic"
13
#endif
14
15
#include "dict0dict.h"
16
#include "btr0btr.h"
17
#include "mach0data.h"
18
#include "trx0rseg.h"
19
#include "trx0trx.h"
20
#include "trx0roll.h"
21
#include "trx0undo.h"
22
#include "trx0purge.h"
23
#include "trx0rec.h"
24
#include "que0que.h"
25
#include "row0row.h"
26
#include "row0upd.h"
27
#include "rem0cmp.h"
28
#include "read0read.h"
29
30
/*************************************************************************
31
Reads the trx id or roll ptr field from a clustered index record: this function
32
is slower than the specialized inline functions. */
33
34
dulint
35
row_get_rec_sys_field(
36
/*==================*/
37
				/* out: value of the field */
38
	ulint		type,	/* in: DATA_TRX_ID or DATA_ROLL_PTR */
39
	rec_t*		rec,	/* in: record */
40
	dict_index_t*	index,	/* in: clustered index */
41
	const ulint*	offsets)/* in: rec_get_offsets(rec, index) */
42
{
43
	ulint		pos;
44
	byte*		field;
45
	ulint		len;
46
47
	ut_ad(index->type & DICT_CLUSTERED);
48
49
	pos = dict_index_get_sys_col_pos(index, type);
50
51
	field = rec_get_nth_field(rec, offsets, pos, &len);
52
53
	if (type == DATA_TRX_ID) {
54
55
		return(trx_read_trx_id(field));
56
	} else {
57
		ut_ad(type == DATA_ROLL_PTR);
58
59
		return(trx_read_roll_ptr(field));
60
	}
61
}
62
63
/*************************************************************************
64
Sets the trx id or roll ptr field in a clustered index record: this function
65
is slower than the specialized inline functions. */
66
67
void
68
row_set_rec_sys_field(
69
/*==================*/
70
				/* out: value of the field */
71
	ulint		type,	/* in: DATA_TRX_ID or DATA_ROLL_PTR */
72
	rec_t*		rec,	/* in: record */
73
	dict_index_t*	index,	/* in: clustered index */
74
	const ulint*	offsets,/* in: rec_get_offsets(rec, index) */
75
	dulint		val)	/* in: value to set */
76
{
77
	ulint	pos;
78
	byte*	field;
79
	ulint	len;
80
81
	ut_ad(index->type & DICT_CLUSTERED);
82
	ut_ad(rec_offs_validate(rec, index, offsets));
83
84
	pos = dict_index_get_sys_col_pos(index, type);
85
86
	field = rec_get_nth_field(rec, offsets, pos, &len);
87
88
	if (type == DATA_TRX_ID) {
89
90
		trx_write_trx_id(field, val);
91
	} else {
92
		ut_ad(type == DATA_ROLL_PTR);
93
94
		trx_write_roll_ptr(field, val);
95
	}
96
}
97
98
/*********************************************************************
99
When an insert to a table is performed, this function builds the entry which
100
has to be inserted to an index on the table. */
101
102
dtuple_t*
103
row_build_index_entry(
104
/*==================*/
105
				/* out: index entry which should be inserted */
106
	dtuple_t*	row,	/* in: row which should be inserted to the
107
				table */
108
	dict_index_t*	index,	/* in: index on the table */
109
	mem_heap_t*	heap)	/* in: memory heap from which the memory for
110
				the index entry is allocated */
111
{
112
	dtuple_t*	entry;
113
	ulint		entry_len;
114
	dict_field_t*	ind_field;
115
	dfield_t*	dfield;
116
	dfield_t*	dfield2;
117
	ulint		i;
118
	ulint		storage_len;
119
120
	ut_ad(row && index && heap);
121
	ut_ad(dtuple_check_typed(row));
122
123
	entry_len = dict_index_get_n_fields(index);
124
	entry = dtuple_create(heap, entry_len);
125
126
	if (index->type & DICT_UNIVERSAL) {
127
		dtuple_set_n_fields_cmp(entry, entry_len);
128
	} else {
129
		dtuple_set_n_fields_cmp(
130
			entry, dict_index_get_n_unique_in_tree(index));
131
	}
132
133
	for (i = 0; i < entry_len; i++) {
134
		const dict_col_t*	col;
135
		ind_field = dict_index_get_nth_field(index, i);
136
		col = ind_field->col;
137
138
		dfield = dtuple_get_nth_field(entry, i);
139
140
		dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col));
141
142
		dfield_copy(dfield, dfield2);
143
144
		/* If a column prefix index, take only the prefix */
145
		if (ind_field->prefix_len > 0
146
		    && dfield_get_len(dfield2) != UNIV_SQL_NULL) {
147
148
			storage_len = dtype_get_at_most_n_mbchars(
149
				col->prtype, col->mbminlen, col->mbmaxlen,
150
				ind_field->prefix_len,
151
				dfield_get_len(dfield2), dfield2->data);
152
153
			dfield_set_len(dfield, storage_len);
154
		}
155
	}
156
157
	ut_ad(dtuple_check_typed(entry));
158
159
	return(entry);
160
}
161
162
/***********************************************************************
163
An inverse function to dict_row_build_index_entry. Builds a row from a
164
record in a clustered index. */
165
166
dtuple_t*
167
row_build(
168
/*======*/
169
				/* out, own: row built; see the NOTE below! */
170
	ulint		type,	/* in: ROW_COPY_POINTERS or ROW_COPY_DATA;
171
				the latter copies also the data fields to
172
				heap while the first only places pointers to
173
				data fields on the index page, and thus is
174
				more efficient */
175
	dict_index_t*	index,	/* in: clustered index */
176
	rec_t*		rec,	/* in: record in the clustered index;
177
				NOTE: in the case ROW_COPY_POINTERS
178
				the data fields in the row will point
179
				directly into this record, therefore,
180
				the buffer page of this record must be
181
				at least s-latched and the latch held
182
				as long as the row dtuple is used! */
183
	const ulint*	offsets,/* in: rec_get_offsets(rec, index)
184
				or NULL, in which case this function
185
				will invoke rec_get_offsets() */
186
	mem_heap_t*	heap)	/* in: memory heap from which the memory
187
				needed is allocated */
188
{
189
	dtuple_t*	row;
190
	dict_table_t*	table;
191
	dict_field_t*	ind_field;
192
	dfield_t*	dfield;
193
	ulint		n_fields;
194
	byte*		field;
195
	ulint		len;
196
	ulint		row_len;
197
	byte*		buf;
198
	ulint		i;
199
	mem_heap_t*	tmp_heap	= NULL;
200
	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
201
	*offsets_ = (sizeof offsets_) / sizeof *offsets_;
202
203
	ut_ad(index && rec && heap);
204
	ut_ad(index->type & DICT_CLUSTERED);
205
206
	if (!offsets) {
207
		offsets = rec_get_offsets(rec, index, offsets_,
208
					  ULINT_UNDEFINED, &tmp_heap);
209
	} else {
210
		ut_ad(rec_offs_validate(rec, index, offsets));
211
	}
212
213
	if (type != ROW_COPY_POINTERS) {
214
		/* Take a copy of rec to heap */
215
		buf = mem_heap_alloc(heap, rec_offs_size(offsets));
216
		rec = rec_copy(buf, rec, offsets);
217
		/* Avoid a debug assertion in rec_offs_validate(). */
77.1.75 by Monty Taylor
More const-correctness.
218
		rec_offs_make_valid(rec, index, offsets);
1 by brian
clean slate
219
	}
220
221
	table = index->table;
222
	row_len = dict_table_get_n_cols(table);
223
224
	row = dtuple_create(heap, row_len);
225
226
	dtuple_set_info_bits(row, rec_get_info_bits(
227
				     rec, dict_table_is_comp(table)));
228
229
	n_fields = rec_offs_n_fields(offsets);
230
231
	dict_table_copy_types(row, table);
232
233
	for (i = 0; i < n_fields; i++) {
234
		ind_field = dict_index_get_nth_field(index, i);
235
236
		if (ind_field->prefix_len == 0) {
237
238
			const dict_col_t*	col
239
				= dict_field_get_col(ind_field);
240
241
			dfield = dtuple_get_nth_field(row,
242
						      dict_col_get_no(col));
243
			field = rec_get_nth_field(rec, offsets, i, &len);
244
245
			dfield_set_data(dfield, field, len);
246
		}
247
	}
248
249
	ut_ad(dtuple_check_typed(row));
250
251
	if (tmp_heap) {
252
		mem_heap_free(tmp_heap);
253
	}
254
255
	return(row);
256
}
257
258
/***********************************************************************
259
Converts an index record to a typed data tuple. NOTE that externally
260
stored (often big) fields are NOT copied to heap. */
261
262
dtuple_t*
263
row_rec_to_index_entry(
264
/*===================*/
265
				/* out, own: index entry built; see the
266
				NOTE below! */
267
	ulint		type,	/* in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
268
				the former copies also the data fields to
269
				heap as the latter only places pointers to
270
				data fields on the index page */
271
	dict_index_t*	index,	/* in: index */
272
	rec_t*		rec,	/* in: record in the index;
273
				NOTE: in the case ROW_COPY_POINTERS
274
				the data fields in the row will point
275
				directly into this record, therefore,
276
				the buffer page of this record must be
277
				at least s-latched and the latch held
278
				as long as the dtuple is used! */
279
	mem_heap_t*	heap)	/* in: memory heap from which the memory
280
				needed is allocated */
281
{
282
	dtuple_t*	entry;
283
	dfield_t*	dfield;
284
	ulint		i;
285
	byte*		field;
286
	ulint		len;
287
	ulint		rec_len;
288
	byte*		buf;
289
	mem_heap_t*	tmp_heap	= NULL;
290
	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
291
	ulint*		offsets		= offsets_;
292
	*offsets_ = (sizeof offsets_) / sizeof *offsets_;
293
294
	ut_ad(rec && heap && index);
295
296
	offsets = rec_get_offsets(rec, index, offsets,
297
				  ULINT_UNDEFINED, &tmp_heap);
298
299
	if (type == ROW_COPY_DATA) {
300
		/* Take a copy of rec to heap */
301
		buf = mem_heap_alloc(heap, rec_offs_size(offsets));
302
		rec = rec_copy(buf, rec, offsets);
303
		/* Avoid a debug assertion in rec_offs_validate(). */
304
		rec_offs_make_valid(rec, index, offsets);
305
	}
306
307
	rec_len = rec_offs_n_fields(offsets);
308
309
	entry = dtuple_create(heap, rec_len);
310
311
	dtuple_set_n_fields_cmp(entry,
312
				dict_index_get_n_unique_in_tree(index));
313
	ut_ad(rec_len == dict_index_get_n_fields(index));
314
315
	dict_index_copy_types(entry, index, rec_len);
316
317
	dtuple_set_info_bits(entry,
318
			     rec_get_info_bits(rec, rec_offs_comp(offsets)));
319
320
	for (i = 0; i < rec_len; i++) {
321
322
		dfield = dtuple_get_nth_field(entry, i);
323
		field = rec_get_nth_field(rec, offsets, i, &len);
324
325
		dfield_set_data(dfield, field, len);
326
	}
327
328
	ut_ad(dtuple_check_typed(entry));
329
	if (tmp_heap) {
330
		mem_heap_free(tmp_heap);
331
	}
332
333
	return(entry);
334
}
335
336
/***********************************************************************
337
Builds from a secondary index record a row reference with which we can
338
search the clustered index record. */
339
340
dtuple_t*
341
row_build_row_ref(
342
/*==============*/
343
				/* out, own: row reference built; see the
344
				NOTE below! */
345
	ulint		type,	/* in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
346
				the former copies also the data fields to
347
				heap, whereas the latter only places pointers
348
				to data fields on the index page */
349
	dict_index_t*	index,	/* in: index */
350
	rec_t*		rec,	/* in: record in the index;
351
				NOTE: in the case ROW_COPY_POINTERS
352
				the data fields in the row will point
353
				directly into this record, therefore,
354
				the buffer page of this record must be
355
				at least s-latched and the latch held
356
				as long as the row reference is used! */
357
	mem_heap_t*	heap)	/* in: memory heap from which the memory
358
				needed is allocated */
359
{
360
	dict_table_t*	table;
361
	dict_index_t*	clust_index;
362
	dfield_t*	dfield;
363
	dtuple_t*	ref;
364
	byte*		field;
365
	ulint		len;
366
	ulint		ref_len;
367
	ulint		pos;
368
	byte*		buf;
369
	ulint		clust_col_prefix_len;
370
	ulint		i;
371
	mem_heap_t*	tmp_heap	= NULL;
372
	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
373
	ulint*		offsets		= offsets_;
374
	*offsets_ = (sizeof offsets_) / sizeof *offsets_;
375
376
	ut_ad(index && rec && heap);
377
378
	offsets = rec_get_offsets(rec, index, offsets,
379
				  ULINT_UNDEFINED, &tmp_heap);
380
381
	if (type == ROW_COPY_DATA) {
382
		/* Take a copy of rec to heap */
383
384
		buf = mem_heap_alloc(heap, rec_offs_size(offsets));
385
386
		rec = rec_copy(buf, rec, offsets);
387
		/* Avoid a debug assertion in rec_offs_validate(). */
388
		rec_offs_make_valid(rec, index, offsets);
389
	}
390
391
	table = index->table;
392
393
	clust_index = dict_table_get_first_index(table);
394
395
	ref_len = dict_index_get_n_unique(clust_index);
396
397
	ref = dtuple_create(heap, ref_len);
398
399
	dict_index_copy_types(ref, clust_index, ref_len);
400
401
	for (i = 0; i < ref_len; i++) {
402
		dfield = dtuple_get_nth_field(ref, i);
403
404
		pos = dict_index_get_nth_field_pos(index, clust_index, i);
405
406
		ut_a(pos != ULINT_UNDEFINED);
407
408
		field = rec_get_nth_field(rec, offsets, pos, &len);
409
410
		dfield_set_data(dfield, field, len);
411
412
		/* If the primary key contains a column prefix, then the
413
		secondary index may contain a longer prefix of the same
414
		column, or the full column, and we must adjust the length
415
		accordingly. */
416
417
		clust_col_prefix_len = dict_index_get_nth_field(
418
			clust_index, i)->prefix_len;
419
420
		if (clust_col_prefix_len > 0) {
421
			if (len != UNIV_SQL_NULL) {
422
423
				const dtype_t*	dtype
424
					= dfield_get_type(dfield);
425
426
				dfield_set_len(dfield,
427
					       dtype_get_at_most_n_mbchars(
428
						       dtype->prtype,
429
						       dtype->mbminlen,
430
						       dtype->mbmaxlen,
431
						       clust_col_prefix_len,
432
						       len, (char*) field));
433
			}
434
		}
435
	}
436
437
	ut_ad(dtuple_check_typed(ref));
438
	if (tmp_heap) {
439
		mem_heap_free(tmp_heap);
440
	}
441
442
	return(ref);
443
}
444
445
/***********************************************************************
446
Builds from a secondary index record a row reference with which we can
447
search the clustered index record. */
448
449
void
450
row_build_row_ref_in_tuple(
451
/*=======================*/
452
	dtuple_t*	ref,	/* in/out: row reference built; see the
453
				NOTE below! */
454
	dict_index_t*	index,	/* in: index */
455
	rec_t*		rec,	/* in: record in the index;
456
				NOTE: the data fields in ref will point
457
				directly into this record, therefore,
458
				the buffer page of this record must be
459
				at least s-latched and the latch held
460
				as long as the row reference is used! */
461
	trx_t*		trx)	/* in: transaction */
462
{
463
	dict_index_t*	clust_index;
464
	dfield_t*	dfield;
465
	byte*		field;
466
	ulint		len;
467
	ulint		ref_len;
468
	ulint		pos;
469
	ulint		clust_col_prefix_len;
470
	ulint		i;
471
	mem_heap_t*	heap		= NULL;
472
	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
473
	ulint*		offsets		= offsets_;
474
	*offsets_ = (sizeof offsets_) / sizeof *offsets_;
475
476
	ut_a(ref);
477
	ut_a(index);
478
	ut_a(rec);
479
480
	if (UNIV_UNLIKELY(!index->table)) {
481
		fputs("InnoDB: table ", stderr);
482
notfound:
483
		ut_print_name(stderr, trx, TRUE, index->table_name);
484
		fputs(" for index ", stderr);
485
		ut_print_name(stderr, trx, FALSE, index->name);
486
		fputs(" not found\n", stderr);
487
		ut_error;
488
	}
489
490
	clust_index = dict_table_get_first_index(index->table);
491
492
	if (!clust_index) {
493
		fputs("InnoDB: clust index for table ", stderr);
494
		goto notfound;
495
	}
496
497
	offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
498
499
	ref_len = dict_index_get_n_unique(clust_index);
500
501
	ut_ad(ref_len == dtuple_get_n_fields(ref));
502
503
	dict_index_copy_types(ref, clust_index, ref_len);
504
505
	for (i = 0; i < ref_len; i++) {
506
		dfield = dtuple_get_nth_field(ref, i);
507
508
		pos = dict_index_get_nth_field_pos(index, clust_index, i);
509
510
		ut_a(pos != ULINT_UNDEFINED);
511
512
		field = rec_get_nth_field(rec, offsets, pos, &len);
513
514
		dfield_set_data(dfield, field, len);
515
516
		/* If the primary key contains a column prefix, then the
517
		secondary index may contain a longer prefix of the same
518
		column, or the full column, and we must adjust the length
519
		accordingly. */
520
521
		clust_col_prefix_len = dict_index_get_nth_field(
522
			clust_index, i)->prefix_len;
523
524
		if (clust_col_prefix_len > 0) {
525
			if (len != UNIV_SQL_NULL) {
526
527
				const dtype_t*	dtype
528
					= dfield_get_type(dfield);
529
530
				dfield_set_len(dfield,
531
					       dtype_get_at_most_n_mbchars(
532
						       dtype->prtype,
533
						       dtype->mbminlen,
534
						       dtype->mbmaxlen,
535
						       clust_col_prefix_len,
536
						       len, (char*) field));
537
			}
538
		}
539
	}
540
541
	ut_ad(dtuple_check_typed(ref));
542
	if (UNIV_LIKELY_NULL(heap)) {
543
		mem_heap_free(heap);
544
	}
545
}
546
547
/***********************************************************************
548
From a row build a row reference with which we can search the clustered
549
index record. */
550
551
void
552
row_build_row_ref_from_row(
553
/*=======================*/
554
	dtuple_t*	ref,	/* in/out: row reference built; see the
555
				NOTE below! ref must have the right number
556
				of fields! */
557
	dict_table_t*	table,	/* in: table */
558
	dtuple_t*	row)	/* in: row
559
				NOTE: the data fields in ref will point
560
				directly into data of this row */
561
{
562
	dict_index_t*	clust_index;
563
	ulint		ref_len;
564
	ulint		i;
565
566
	ut_ad(ref && table && row);
567
568
	clust_index = dict_table_get_first_index(table);
569
570
	ref_len = dict_index_get_n_unique(clust_index);
571
572
	ut_ad(ref_len == dtuple_get_n_fields(ref));
573
574
	for (i = 0; i < ref_len; i++) {
575
		const dict_col_t*	col;
576
		dict_field_t*		field;
577
		dfield_t*		dfield;
578
		dfield_t*		dfield2;
579
580
		dfield = dtuple_get_nth_field(ref, i);
581
582
		field = dict_index_get_nth_field(clust_index, i);
583
584
		col = dict_field_get_col(field);
585
586
		dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col));
587
588
		dfield_copy(dfield, dfield2);
589
590
		if (field->prefix_len > 0
591
		    && dfield->len != UNIV_SQL_NULL) {
592
593
			dfield->len = dtype_get_at_most_n_mbchars(
594
				col->prtype, col->mbminlen, col->mbmaxlen,
595
				field->prefix_len, dfield->len, dfield->data);
596
		}
597
	}
598
599
	ut_ad(dtuple_check_typed(ref));
600
}
601
602
/*******************************************************************
603
Searches the clustered index record for a row, if we have the row reference. */
604
605
ibool
606
row_search_on_row_ref(
607
/*==================*/
608
				/* out: TRUE if found */
609
	btr_pcur_t*	pcur,	/* in/out: persistent cursor, which must
610
				be closed by the caller */
611
	ulint		mode,	/* in: BTR_MODIFY_LEAF, ... */
612
	dict_table_t*	table,	/* in: table */
613
	dtuple_t*	ref,	/* in: row reference */
614
	mtr_t*		mtr)	/* in: mtr */
615
{
616
	ulint		low_match;
617
	rec_t*		rec;
618
	dict_index_t*	index;
619
620
	ut_ad(dtuple_check_typed(ref));
621
622
	index = dict_table_get_first_index(table);
623
624
	ut_a(dtuple_get_n_fields(ref) == dict_index_get_n_unique(index));
625
626
	btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr);
627
628
	low_match = btr_pcur_get_low_match(pcur);
629
630
	rec = btr_pcur_get_rec(pcur);
631
632
	if (page_rec_is_infimum(rec)) {
633
634
		return(FALSE);
635
	}
636
637
	if (low_match != dtuple_get_n_fields(ref)) {
638
639
		return(FALSE);
640
	}
641
642
	return(TRUE);
643
}
644
645
/*************************************************************************
646
Fetches the clustered index record for a secondary index record. The latches
647
on the secondary index record are preserved. */
648
649
rec_t*
650
row_get_clust_rec(
651
/*==============*/
652
				/* out: record or NULL, if no record found */
653
	ulint		mode,	/* in: BTR_MODIFY_LEAF, ... */
654
	rec_t*		rec,	/* in: record in a secondary index */
655
	dict_index_t*	index,	/* in: secondary index */
656
	dict_index_t**	clust_index,/* out: clustered index */
657
	mtr_t*		mtr)	/* in: mtr */
658
{
659
	mem_heap_t*	heap;
660
	dtuple_t*	ref;
661
	dict_table_t*	table;
662
	btr_pcur_t	pcur;
663
	ibool		found;
664
	rec_t*		clust_rec;
665
666
	ut_ad((index->type & DICT_CLUSTERED) == 0);
667
668
	table = index->table;
669
670
	heap = mem_heap_create(256);
671
672
	ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
673
674
	found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
675
676
	clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
677
678
	mem_heap_free(heap);
679
680
	btr_pcur_close(&pcur);
681
682
	*clust_index = dict_table_get_first_index(table);
683
684
	return(clust_rec);
685
}
686
687
/*******************************************************************
688
Searches an index record. */
689
690
ibool
691
row_search_index_entry(
692
/*===================*/
693
				/* out: TRUE if found */
694
	dict_index_t*	index,	/* in: index */
695
	dtuple_t*	entry,	/* in: index entry */
696
	ulint		mode,	/* in: BTR_MODIFY_LEAF, ... */
697
	btr_pcur_t*	pcur,	/* in/out: persistent cursor, which must
698
				be closed by the caller */
699
	mtr_t*		mtr)	/* in: mtr */
700
{
701
	ulint	n_fields;
702
	ulint	low_match;
703
	rec_t*	rec;
704
705
	ut_ad(dtuple_check_typed(entry));
706
707
	btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
708
	low_match = btr_pcur_get_low_match(pcur);
709
710
	rec = btr_pcur_get_rec(pcur);
711
712
	n_fields = dtuple_get_n_fields(entry);
713
714
	if (page_rec_is_infimum(rec)) {
715
716
		return(FALSE);
717
	}
718
719
	if (low_match != n_fields) {
720
		/* Not found */
721
722
		return(FALSE);
723
	}
724
725
	return(TRUE);
726
}