~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
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
16
17
*****************************************************************************/
18
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
19
/***********************************************************************
20
Comparison services for records
21
22
Created 7/1/1994 Heikki Tuuri
23
************************************************************************/
24
25
#include "rem0cmp.h"
26
27
#ifdef UNIV_NONINL
28
#include "rem0cmp.ic"
29
#endif
30
31
#include "srv0srv.h"
32
33
/*		ALPHABETICAL ORDER
34
		==================
35
36
The records are put into alphabetical order in the following
37
way: let F be the first field where two records disagree.
38
If there is a character in some position n where the the
39
records disagree, the order is determined by comparison of
40
the characters at position n, possibly after
41
collating transformation. If there is no such character,
42
but the corresponding fields have different lengths, then
43
if the data type of the fields is paddable,
44
shorter field is padded with a padding character. If the
45
data type is not paddable, longer field is considered greater.
46
Finally, the SQL null is bigger than any other value.
47
48
At the present, the comparison functions return 0 in the case,
49
where two records disagree only in the way that one
50
has more fields than the other. */
51
52
#ifdef UNIV_DEBUG
53
/*****************************************************************
54
Used in debug checking of cmp_dtuple_... .
55
This function is used to compare a data tuple to a physical record. If
56
dtuple has n fields then rec must have either m >= n fields, or it must
57
differ from dtuple in some of the m fields rec has. */
58
static
59
int
60
cmp_debug_dtuple_rec_with_match(
61
/*============================*/
62
				/* out: 1, 0, -1, if dtuple is greater, equal,
63
				less than rec, respectively, when only the
64
				common first fields are compared */
65
	const dtuple_t*	dtuple,	/* in: data tuple */
66
	const rec_t*	rec,	/* in: physical record which differs from
67
				dtuple in some of the common fields, or which
68
				has an equal number or more fields than
69
				dtuple */
70
	const ulint*	offsets,/* in: array returned by rec_get_offsets() */
71
	ulint*		matched_fields);/* in/out: number of already
72
				completely  matched fields; when function
73
				returns, contains the value for current
74
				comparison */
75
#endif /* UNIV_DEBUG */
76
#ifndef UNIV_HOTBACKUP
77
/*****************************************************************
78
This function is used to compare two data fields for which the data type
79
is such that we must use MySQL code to compare them. The prototype here
80
must be a copy of the the one in ha_innobase.cc! */
81
extern
82
int
83
innobase_mysql_cmp(
84
/*===============*/
85
					/* out: 1, 0, -1, if a is greater,
86
					equal, less than b, respectively */
87
	int		mysql_type,	/* in: MySQL type */
88
	uint		charset_number,	/* in: number of the charset */
89
	const unsigned char* a,		/* in: data field */
90
	unsigned int	a_length,	/* in: data field length,
91
					not UNIV_SQL_NULL */
92
	const unsigned char* b,		/* in: data field */
93
	unsigned int	b_length);	/* in: data field length,
94
					not UNIV_SQL_NULL */
95
#endif /* !UNIV_HOTBACKUP */
96
/*************************************************************************
97
Transforms the character code so that it is ordered appropriately for the
98
language. This is only used for the latin1 char set. MySQL does the
99
comparisons for other char sets. */
100
UNIV_INLINE
101
ulint
102
cmp_collate(
103
/*========*/
104
			/* out: collation order position */
105
	ulint	code)	/* in: code of a character stored in database record */
106
{
107
	return((ulint) srv_latin1_ordering[code]);
108
}
109
110
/*****************************************************************
111
Returns TRUE if two columns are equal for comparison purposes. */
112
UNIV_INTERN
113
ibool
114
cmp_cols_are_equal(
115
/*===============*/
116
					/* out: TRUE if the columns are
117
					considered equal in comparisons */
118
	const dict_col_t*	col1,	/* in: column 1 */
119
	const dict_col_t*	col2,	/* in: column 2 */
120
	ibool			check_charsets)
121
					/* in: whether to check charsets */
122
{
123
	if (dtype_is_non_binary_string_type(col1->mtype, col1->prtype)
124
	    && dtype_is_non_binary_string_type(col2->mtype, col2->prtype)) {
125
126
		/* Both are non-binary string types: they can be compared if
127
		and only if the charset-collation is the same */
128
129
		if (check_charsets) {
130
			return(dtype_get_charset_coll(col1->prtype)
131
			       == dtype_get_charset_coll(col2->prtype));
132
		} else {
133
			return(TRUE);
134
		}
135
	}
136
137
	if (dtype_is_binary_string_type(col1->mtype, col1->prtype)
138
	    && dtype_is_binary_string_type(col2->mtype, col2->prtype)) {
139
140
		/* Both are binary string types: they can be compared */
141
142
		return(TRUE);
143
	}
144
145
	if (col1->mtype != col2->mtype) {
146
147
		return(FALSE);
148
	}
149
150
	if (col1->mtype == DATA_INT
151
	    && (col1->prtype & DATA_UNSIGNED)
152
	    != (col2->prtype & DATA_UNSIGNED)) {
153
154
		/* The storage format of an unsigned integer is different
155
		from a signed integer: in a signed integer we OR
156
		0x8000... to the value of positive integers. */
157
158
		return(FALSE);
159
	}
160
161
	return(col1->mtype != DATA_INT || col1->len == col2->len);
162
}
163
164
#ifndef UNIV_HOTBACKUP
165
/*****************************************************************
166
Innobase uses this function to compare two data fields for which the data type
167
is such that we must compare whole fields or call MySQL to do the comparison */
168
static
169
int
170
cmp_whole_field(
171
/*============*/
172
					/* out: 1, 0, -1, if a is greater,
173
					equal, less than b, respectively */
174
	ulint		mtype,		/* in: main type */
175
	ulint		prtype,		/* in: precise type */
176
	const byte*	a,		/* in: data field */
177
	unsigned int	a_length,	/* in: data field length,
178
					not UNIV_SQL_NULL */
179
	const byte*	b,		/* in: data field */
180
	unsigned int	b_length)	/* in: data field length,
181
					not UNIV_SQL_NULL */
182
{
183
	float		f_1;
184
	float		f_2;
185
	double		d_1;
186
	double		d_2;
187
	int		swap_flag	= 1;
188
189
	switch (mtype) {
190
191
	case DATA_DECIMAL:
192
		/* Remove preceding spaces */
193
		for (; a_length && *a == ' '; a++, a_length--);
194
		for (; b_length && *b == ' '; b++, b_length--);
195
196
		if (*a == '-') {
197
			if (*b != '-') {
198
				return(-1);
199
			}
200
201
			a++; b++;
202
			a_length--;
203
			b_length--;
204
205
			swap_flag = -1;
206
207
		} else if (*b == '-') {
208
209
			return(1);
210
		}
211
212
		while (a_length > 0 && (*a == '+' || *a == '0')) {
213
			a++; a_length--;
214
		}
215
216
		while (b_length > 0 && (*b == '+' || *b == '0')) {
217
			b++; b_length--;
218
		}
219
220
		if (a_length != b_length) {
221
			if (a_length < b_length) {
222
				return(-swap_flag);
223
			}
224
225
			return(swap_flag);
226
		}
227
228
		while (a_length > 0 && *a == *b) {
229
230
			a++; b++; a_length--;
231
		}
232
233
		if (a_length == 0) {
234
235
			return(0);
236
		}
237
238
		if (*a > *b) {
239
			return(swap_flag);
240
		}
241
242
		return(-swap_flag);
243
	case DATA_DOUBLE:
244
		d_1 = mach_double_read(a);
245
		d_2 = mach_double_read(b);
246
247
		if (d_1 > d_2) {
248
			return(1);
249
		} else if (d_2 > d_1) {
250
			return(-1);
251
		}
252
253
		return(0);
254
255
	case DATA_FLOAT:
256
		f_1 = mach_float_read(a);
257
		f_2 = mach_float_read(b);
258
259
		if (f_1 > f_2) {
260
			return(1);
261
		} else if (f_2 > f_1) {
262
			return(-1);
263
		}
264
265
		return(0);
266
	case DATA_BLOB:
267
		if (prtype & DATA_BINARY_TYPE) {
268
269
			ut_print_timestamp(stderr);
270
			fprintf(stderr,
271
				"  InnoDB: Error: comparing a binary BLOB"
272
				" with a character set sensitive\n"
273
				"InnoDB: comparison!\n");
274
		}
275
		/* fall through */
276
	case DATA_VARMYSQL:
277
	case DATA_MYSQL:
278
		return(innobase_mysql_cmp(
279
			       (int)(prtype & DATA_MYSQL_TYPE_MASK),
280
			       (uint)dtype_get_charset_coll(prtype),
281
			       a, a_length, b, b_length));
282
	default:
283
		fprintf(stderr,
284
			"InnoDB: unknown type number %lu\n",
285
			(ulong) mtype);
286
		ut_error;
287
	}
288
289
	return(0);
290
}
291
#endif /* !UNIV_HOTBACKUP */
292
293
/*****************************************************************
294
This function is used to compare two data fields for which we know the
295
data type. */
296
UNIV_INTERN
297
int
298
cmp_data_data_slow(
299
/*===============*/
300
				/* out: 1, 0, -1, if data1 is greater, equal,
301
				less than data2, respectively */
302
	ulint		mtype,	/* in: main type */
303
	ulint		prtype,	/* in: precise type */
304
	const byte*	data1,	/* in: data field (== a pointer to a memory
305
				buffer) */
306
	ulint		len1,	/* in: data field length or UNIV_SQL_NULL */
307
	const byte*	data2,	/* in: data field (== a pointer to a memory
308
				buffer) */
309
	ulint		len2)	/* in: data field length or UNIV_SQL_NULL */
310
{
311
#ifndef UNIV_HOTBACKUP
312
	ulint	data1_byte;
313
	ulint	data2_byte;
314
	ulint	cur_bytes;
315
316
	if (len1 == UNIV_SQL_NULL || len2 == UNIV_SQL_NULL) {
317
318
		if (len1 == len2) {
319
320
			return(0);
321
		}
322
323
		if (len1 == UNIV_SQL_NULL) {
324
			/* We define the SQL null to be the smallest possible
325
			value of a field in the alphabetical order */
326
327
			return(-1);
328
		}
329
330
		return(1);
331
	}
332
333
	if (mtype >= DATA_FLOAT
334
	    || (mtype == DATA_BLOB
335
		&& 0 == (prtype & DATA_BINARY_TYPE)
336
		&& dtype_get_charset_coll(prtype)
337
		!= DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
338
339
		return(cmp_whole_field(mtype, prtype,
340
				       data1, (unsigned) len1,
341
				       data2, (unsigned) len2));
342
	}
343
344
	/* Compare then the fields */
345
346
	cur_bytes = 0;
347
348
	for (;;) {
349
		if (len1 <= cur_bytes) {
350
			if (len2 <= cur_bytes) {
351
352
				return(0);
353
			}
354
355
			data1_byte = dtype_get_pad_char(mtype, prtype);
356
357
			if (data1_byte == ULINT_UNDEFINED) {
358
359
				return(-1);
360
			}
361
		} else {
362
			data1_byte = *data1;
363
		}
364
365
		if (len2 <= cur_bytes) {
366
			data2_byte = dtype_get_pad_char(mtype, prtype);
367
368
			if (data2_byte == ULINT_UNDEFINED) {
369
370
				return(1);
371
			}
372
		} else {
373
			data2_byte = *data2;
374
		}
375
376
		if (data1_byte == data2_byte) {
377
			/* If the bytes are equal, they will remain such even
378
			after the collation transformation below */
379
380
			goto next_byte;
381
		}
382
383
		if (mtype <= DATA_CHAR
384
		    || (mtype == DATA_BLOB
385
			&& 0 == (prtype & DATA_BINARY_TYPE))) {
386
387
			data1_byte = cmp_collate(data1_byte);
388
			data2_byte = cmp_collate(data2_byte);
389
		}
390
391
		if (data1_byte > data2_byte) {
392
393
			return(1);
394
		} else if (data1_byte < data2_byte) {
395
396
			return(-1);
397
		}
398
next_byte:
399
		/* Next byte */
400
		cur_bytes++;
401
		data1++;
402
		data2++;
403
	}
404
#else /* !UNIV_HOTBACKUP */
405
	/* This function depends on MySQL code that is not included in
406
	InnoDB Hot Backup builds.  Besides, this function should never
407
	be called in InnoDB Hot Backup. */
408
	ut_error;
409
#endif /* !UNIV_HOTBACKUP */
410
411
}
412
413
/*****************************************************************
414
This function is used to compare a data tuple to a physical record.
415
Only dtuple->n_fields_cmp first fields are taken into account for
416
the the data tuple! If we denote by n = n_fields_cmp, then rec must
417
have either m >= n fields, or it must differ from dtuple in some of
418
the m fields rec has. If rec has an externally stored field we do not
419
compare it but return with value 0 if such a comparison should be
420
made. */
421
UNIV_INTERN
422
int
423
cmp_dtuple_rec_with_match(
424
/*======================*/
425
				/* out: 1, 0, -1, if dtuple is greater, equal,
426
				less than rec, respectively, when only the
427
				common first fields are compared, or
428
				until the first externally stored field in
429
				rec */
430
	const dtuple_t*	dtuple,	/* in: data tuple */
431
	const rec_t*	rec,	/* in: physical record which differs from
432
				dtuple in some of the common fields, or which
433
				has an equal number or more fields than
434
				dtuple */
435
	const ulint*	offsets,/* in: array returned by rec_get_offsets() */
436
	ulint*		matched_fields, /* in/out: number of already completely
437
				matched fields; when function returns,
438
				contains the value for current comparison */
439
	ulint*		matched_bytes) /* in/out: number of already matched
440
				bytes within the first field not completely
441
				matched; when function returns, contains the
442
				value for current comparison */
443
{
444
#ifndef UNIV_HOTBACKUP
445
	const dfield_t*	dtuple_field;	/* current field in logical record */
446
	ulint		dtuple_f_len;	/* the length of the current field
447
					in the logical record */
448
	const byte*	dtuple_b_ptr;	/* pointer to the current byte in
449
					logical field data */
450
	ulint		dtuple_byte;	/* value of current byte to be compared
451
					in dtuple*/
452
	ulint		rec_f_len;	/* length of current field in rec */
453
	const byte*	rec_b_ptr;	/* pointer to the current byte in
454
					rec field */
455
	ulint		rec_byte;	/* value of current byte to be
456
					compared in rec */
457
	ulint		cur_field;	/* current field number */
458
	ulint		cur_bytes;	/* number of already matched bytes
459
					in current field */
460
	int		ret = 3333;	/* return value */
461
462
	ut_ad(dtuple && rec && matched_fields && matched_bytes);
463
	ut_ad(dtuple_check_typed(dtuple));
464
	ut_ad(rec_offs_validate(rec, NULL, offsets));
465
466
	cur_field = *matched_fields;
467
	cur_bytes = *matched_bytes;
468
469
	ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple));
470
	ut_ad(cur_field <= rec_offs_n_fields(offsets));
471
472
	if (cur_bytes == 0 && cur_field == 0) {
473
		ulint	rec_info = rec_get_info_bits(rec,
474
						     rec_offs_comp(offsets));
475
		ulint	tup_info = dtuple_get_info_bits(dtuple);
476
477
		if (UNIV_UNLIKELY(rec_info & REC_INFO_MIN_REC_FLAG)) {
478
			ret = !(tup_info & REC_INFO_MIN_REC_FLAG);
479
			goto order_resolved;
480
		} else if (UNIV_UNLIKELY(tup_info & REC_INFO_MIN_REC_FLAG)) {
481
			ret = -1;
482
			goto order_resolved;
483
		}
484
	}
485
486
	/* Match fields in a loop; stop if we run out of fields in dtuple
487
	or find an externally stored field */
488
489
	while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
490
491
		ulint	mtype;
492
		ulint	prtype;
493
494
		dtuple_field = dtuple_get_nth_field(dtuple, cur_field);
495
		{
496
			const dtype_t*	type
497
				= dfield_get_type(dtuple_field);
498
499
			mtype = type->mtype;
500
			prtype = type->prtype;
501
		}
502
503
		dtuple_f_len = dfield_get_len(dtuple_field);
504
505
		rec_b_ptr = rec_get_nth_field(rec, offsets,
506
					      cur_field, &rec_f_len);
507
508
		/* If we have matched yet 0 bytes, it may be that one or
509
		both the fields are SQL null, or the record or dtuple may be
510
		the predefined minimum record, or the field is externally
511
		stored */
512
513
		if (UNIV_LIKELY(cur_bytes == 0)) {
514
			if (rec_offs_nth_extern(offsets, cur_field)) {
515
				/* We do not compare to an externally
516
				stored field */
517
518
				ret = 0;
519
520
				goto order_resolved;
521
			}
522
523
			if (dtuple_f_len == UNIV_SQL_NULL) {
524
				if (rec_f_len == UNIV_SQL_NULL) {
525
526
					goto next_field;
527
				}
528
529
				ret = -1;
530
				goto order_resolved;
531
			} else if (rec_f_len == UNIV_SQL_NULL) {
532
				/* We define the SQL null to be the
533
				smallest possible value of a field
534
				in the alphabetical order */
535
536
				ret = 1;
537
				goto order_resolved;
538
			}
539
		}
540
541
		if (mtype >= DATA_FLOAT
542
		    || (mtype == DATA_BLOB
543
			&& 0 == (prtype & DATA_BINARY_TYPE)
544
			&& dtype_get_charset_coll(prtype)
545
			!= DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
546
547
			ret = cmp_whole_field(mtype, prtype,
548
					      dfield_get_data(dtuple_field),
549
					      (unsigned) dtuple_f_len,
550
					      rec_b_ptr, (unsigned) rec_f_len);
551
552
			if (ret != 0) {
553
				cur_bytes = 0;
554
555
				goto order_resolved;
556
			} else {
557
				goto next_field;
558
			}
559
		}
560
561
		/* Set the pointers at the current byte */
562
563
		rec_b_ptr = rec_b_ptr + cur_bytes;
564
		dtuple_b_ptr = (byte*)dfield_get_data(dtuple_field)
565
			+ cur_bytes;
566
		/* Compare then the fields */
567
568
		for (;;) {
569
			if (UNIV_UNLIKELY(rec_f_len <= cur_bytes)) {
570
				if (dtuple_f_len <= cur_bytes) {
571
572
					goto next_field;
573
				}
574
575
				rec_byte = dtype_get_pad_char(mtype, prtype);
576
577
				if (rec_byte == ULINT_UNDEFINED) {
578
					ret = 1;
579
580
					goto order_resolved;
581
				}
582
			} else {
583
				rec_byte = *rec_b_ptr;
584
			}
585
586
			if (UNIV_UNLIKELY(dtuple_f_len <= cur_bytes)) {
587
				dtuple_byte = dtype_get_pad_char(mtype,
588
								 prtype);
589
590
				if (dtuple_byte == ULINT_UNDEFINED) {
591
					ret = -1;
592
593
					goto order_resolved;
594
				}
595
			} else {
596
				dtuple_byte = *dtuple_b_ptr;
597
			}
598
599
			if (dtuple_byte == rec_byte) {
600
				/* If the bytes are equal, they will
601
				remain such even after the collation
602
				transformation below */
603
604
				goto next_byte;
605
			}
606
607
			if (mtype <= DATA_CHAR
608
			    || (mtype == DATA_BLOB
609
				&& !(prtype & DATA_BINARY_TYPE))) {
610
611
				rec_byte = cmp_collate(rec_byte);
612
				dtuple_byte = cmp_collate(dtuple_byte);
613
			}
614
615
			ret = (int) (dtuple_byte - rec_byte);
616
			if (UNIV_LIKELY(ret)) {
617
				if (ret < 0) {
618
					ret = -1;
619
					goto order_resolved;
620
				} else {
621
					ret = 1;
622
					goto order_resolved;
623
				}
624
			}
625
next_byte:
626
			/* Next byte */
627
			cur_bytes++;
628
			rec_b_ptr++;
629
			dtuple_b_ptr++;
630
		}
631
632
next_field:
633
		cur_field++;
634
		cur_bytes = 0;
635
	}
636
637
	ut_ad(cur_bytes == 0);
638
639
	ret = 0;	/* If we ran out of fields, dtuple was equal to rec
640
			up to the common fields */
641
order_resolved:
642
	ut_ad((ret >= - 1) && (ret <= 1));
643
	ut_ad(ret == cmp_debug_dtuple_rec_with_match(dtuple, rec, offsets,
644
						     matched_fields));
645
	ut_ad(*matched_fields == cur_field); /* In the debug version, the
646
					     above cmp_debug_... sets
647
					     *matched_fields to a value */
648
	*matched_fields = cur_field;
649
	*matched_bytes = cur_bytes;
650
651
	return(ret);
652
#else /* !UNIV_HOTBACKUP */
653
	/* This function depends on MySQL code that is not included in
654
	InnoDB Hot Backup builds.  Besides, this function should never
655
	be called in InnoDB Hot Backup. */
656
	ut_error;
657
	return(0);
658
#endif /* !UNIV_HOTBACKUP */
659
}
660
661
/******************************************************************
662
Compares a data tuple to a physical record. */
663
UNIV_INTERN
664
int
665
cmp_dtuple_rec(
666
/*===========*/
667
				/* out: 1, 0, -1, if dtuple is greater, equal,
668
				less than rec, respectively; see the comments
669
				for cmp_dtuple_rec_with_match */
670
	const dtuple_t*	dtuple,	/* in: data tuple */
671
	const rec_t*	rec,	/* in: physical record */
672
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
673
{
674
	ulint	matched_fields	= 0;
675
	ulint	matched_bytes	= 0;
676
677
	ut_ad(rec_offs_validate(rec, NULL, offsets));
678
	return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
679
					 &matched_fields, &matched_bytes));
680
}
681
682
/******************************************************************
683
Checks if a dtuple is a prefix of a record. The last field in dtuple
684
is allowed to be a prefix of the corresponding field in the record. */
685
UNIV_INTERN
686
ibool
687
cmp_dtuple_is_prefix_of_rec(
688
/*========================*/
689
				/* out: TRUE if prefix */
690
	const dtuple_t*	dtuple,	/* in: data tuple */
691
	const rec_t*	rec,	/* in: physical record */
692
	const ulint*	offsets)/* in: array returned by rec_get_offsets() */
693
{
694
	ulint	n_fields;
695
	ulint	matched_fields	= 0;
696
	ulint	matched_bytes	= 0;
697
698
	ut_ad(rec_offs_validate(rec, NULL, offsets));
699
	n_fields = dtuple_get_n_fields(dtuple);
700
701
	if (n_fields > rec_offs_n_fields(offsets)) {
702
703
		return(FALSE);
704
	}
705
706
	cmp_dtuple_rec_with_match(dtuple, rec, offsets,
707
				  &matched_fields, &matched_bytes);
708
	if (matched_fields == n_fields) {
709
710
		return(TRUE);
711
	}
712
713
	if (matched_fields == n_fields - 1
714
	    && matched_bytes == dfield_get_len(
715
		    dtuple_get_nth_field(dtuple, n_fields - 1))) {
716
		return(TRUE);
717
	}
718
719
	return(FALSE);
720
}
721
722
#ifndef UNIV_HOTBACKUP
723
/*****************************************************************
724
Compare two physical records that contain the same number of columns,
725
none of which are stored externally. */
726
UNIV_INTERN
727
int
728
cmp_rec_rec_simple(
729
/*===============*/
730
					/* out: 1, 0 , -1 if rec1 is greater,
731
					equal, less, respectively, than rec2 */
732
	const rec_t*		rec1,	/* in: physical record */
733
	const rec_t*		rec2,	/* in: physical record */
734
	const ulint*		offsets1,/* in: rec_get_offsets(rec1, index) */
735
	const ulint*		offsets2,/* in: rec_get_offsets(rec2, index) */
736
	const dict_index_t*	index)	/* in: data dictionary index */
737
{
738
	ulint		rec1_f_len;	/* length of current field in rec1 */
739
	const byte*	rec1_b_ptr;	/* pointer to the current byte
740
					in rec1 field */
741
	ulint		rec1_byte;	/* value of current byte to be
742
					compared in rec1 */
743
	ulint		rec2_f_len;	/* length of current field in rec2 */
744
	const byte*	rec2_b_ptr;	/* pointer to the current byte
745
					in rec2 field */
746
	ulint		rec2_byte;	/* value of current byte to be
747
					compared in rec2 */
748
	ulint		cur_field;	/* current field number */
749
	ulint		n_uniq;
750
751
	n_uniq = dict_index_get_n_unique(index);
752
	ut_ad(rec_offs_n_fields(offsets1) >= n_uniq);
753
	ut_ad(rec_offs_n_fields(offsets2) >= n_uniq);
754
755
	ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2));
756
757
	for (cur_field = 0; cur_field < n_uniq; cur_field++) {
758
759
		ulint	cur_bytes;
760
		ulint	mtype;
761
		ulint	prtype;
762
763
		{
764
			const dict_col_t*	col
765
				= dict_index_get_nth_col(index, cur_field);
766
767
			mtype = col->mtype;
768
			prtype = col->prtype;
769
		}
770
771
		ut_ad(!rec_offs_nth_extern(offsets1, cur_field));
772
		ut_ad(!rec_offs_nth_extern(offsets2, cur_field));
773
774
		rec1_b_ptr = rec_get_nth_field(rec1, offsets1,
775
					       cur_field, &rec1_f_len);
776
		rec2_b_ptr = rec_get_nth_field(rec2, offsets2,
777
					       cur_field, &rec2_f_len);
778
779
		if (rec1_f_len == UNIV_SQL_NULL
780
		    || rec2_f_len == UNIV_SQL_NULL) {
781
782
			if (rec1_f_len == rec2_f_len) {
783
784
				goto next_field;
785
786
			} else if (rec2_f_len == UNIV_SQL_NULL) {
787
788
				/* We define the SQL null to be the
789
				smallest possible value of a field
790
				in the alphabetical order */
791
792
				return(1);
793
			} else {
794
				return(-1);
795
			}
796
		}
797
798
		if (mtype >= DATA_FLOAT
799
		    || (mtype == DATA_BLOB
800
			&& 0 == (prtype & DATA_BINARY_TYPE)
801
			&& dtype_get_charset_coll(prtype)
802
			!= DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
803
			int ret = cmp_whole_field(mtype, prtype,
804
						  rec1_b_ptr,
805
						  (unsigned) rec1_f_len,
806
						  rec2_b_ptr,
807
						  (unsigned) rec2_f_len);
808
			if (ret) {
809
				return(ret);
810
			}
811
812
			goto next_field;
813
		}
814
815
		/* Compare the fields */
816
		for (cur_bytes = 0;; cur_bytes++, rec1_b_ptr++, rec2_b_ptr++) {
817
			if (rec2_f_len <= cur_bytes) {
818
819
				if (rec1_f_len <= cur_bytes) {
820
821
					goto next_field;
822
				}
823
824
				rec2_byte = dtype_get_pad_char(mtype, prtype);
825
826
				if (rec2_byte == ULINT_UNDEFINED) {
827
					return(1);
828
				}
829
			} else {
830
				rec2_byte = *rec2_b_ptr;
831
			}
832
833
			if (rec1_f_len <= cur_bytes) {
834
				rec1_byte = dtype_get_pad_char(mtype, prtype);
835
836
				if (rec1_byte == ULINT_UNDEFINED) {
837
					return(-1);
838
				}
839
			} else {
840
				rec1_byte = *rec1_b_ptr;
841
			}
842
843
			if (rec1_byte == rec2_byte) {
844
				/* If the bytes are equal, they will remain
845
				such even after the collation transformation
846
				below */
847
848
				continue;
849
			}
850
851
			if (mtype <= DATA_CHAR
852
			    || (mtype == DATA_BLOB
853
				&& !(prtype & DATA_BINARY_TYPE))) {
854
855
				rec1_byte = cmp_collate(rec1_byte);
856
				rec2_byte = cmp_collate(rec2_byte);
857
			}
858
859
			if (rec1_byte < rec2_byte) {
860
				return(-1);
861
			} else if (rec1_byte > rec2_byte) {
862
				return(1);
863
			}
864
		}
865
next_field:
866
		continue;
867
	}
868
869
	/* If we ran out of fields, rec1 was equal to rec2. */
870
	return(0);
871
}
872
#endif /* !UNIV_HOTBACKUP */
873
874
/*****************************************************************
875
This function is used to compare two physical records. Only the common
876
first fields are compared, and if an externally stored field is
877
encountered, then 0 is returned. */
878
UNIV_INTERN
879
int
880
cmp_rec_rec_with_match(
881
/*===================*/
882
				/* out: 1, 0 , -1 if rec1 is greater, equal,
883
				less, respectively, than rec2; only the common
884
				first fields are compared */
885
	const rec_t*	rec1,	/* in: physical record */
886
	const rec_t*	rec2,	/* in: physical record */
887
	const ulint*	offsets1,/* in: rec_get_offsets(rec1, index) */
888
	const ulint*	offsets2,/* in: rec_get_offsets(rec2, index) */
889
	dict_index_t*	index,	/* in: data dictionary index */
890
	ulint*		matched_fields, /* in/out: number of already completely
891
				matched fields; when the function returns,
892
				contains the value the for current
893
				comparison */
894
	ulint*		matched_bytes) /* in/out: number of already matched
895
				bytes within the first field not completely
896
				matched; when the function returns, contains
897
				the value for the current comparison */
898
{
899
#ifndef UNIV_HOTBACKUP
900
	ulint		rec1_n_fields;	/* the number of fields in rec */
901
	ulint		rec1_f_len;	/* length of current field in rec */
902
	const byte*	rec1_b_ptr;	/* pointer to the current byte
903
					in rec field */
904
	ulint		rec1_byte;	/* value of current byte to be
905
					compared in rec */
906
	ulint		rec2_n_fields;	/* the number of fields in rec */
907
	ulint		rec2_f_len;	/* length of current field in rec */
908
	const byte*	rec2_b_ptr;	/* pointer to the current byte
909
					in rec field */
910
	ulint		rec2_byte;	/* value of current byte to be
911
					compared in rec */
912
	ulint		cur_field;	/* current field number */
913
	ulint		cur_bytes;	/* number of already matched
914
					bytes in current field */
915
	int		ret = 0;	/* return value */
916
	ulint		comp;
917
918
	ut_ad(rec1 && rec2 && index);
919
	ut_ad(rec_offs_validate(rec1, index, offsets1));
920
	ut_ad(rec_offs_validate(rec2, index, offsets2));
921
	ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2));
922
923
	comp = rec_offs_comp(offsets1);
924
	rec1_n_fields = rec_offs_n_fields(offsets1);
925
	rec2_n_fields = rec_offs_n_fields(offsets2);
926
927
	cur_field = *matched_fields;
928
	cur_bytes = *matched_bytes;
929
930
	/* Match fields in a loop */
931
932
	while ((cur_field < rec1_n_fields) && (cur_field < rec2_n_fields)) {
933
934
		ulint	mtype;
935
		ulint	prtype;
936
937
		if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
938
			/* This is for the insert buffer B-tree. */
939
			mtype = DATA_BINARY;
940
			prtype = 0;
941
		} else {
942
			const dict_col_t*	col
943
				= dict_index_get_nth_col(index, cur_field);
944
945
			mtype = col->mtype;
946
			prtype = col->prtype;
947
		}
948
949
		rec1_b_ptr = rec_get_nth_field(rec1, offsets1,
950
					       cur_field, &rec1_f_len);
951
		rec2_b_ptr = rec_get_nth_field(rec2, offsets2,
952
					       cur_field, &rec2_f_len);
953
954
		if (cur_bytes == 0) {
955
			if (cur_field == 0) {
956
				/* Test if rec is the predefined minimum
957
				record */
958
				if (UNIV_UNLIKELY(rec_get_info_bits(rec1, comp)
959
						  & REC_INFO_MIN_REC_FLAG)) {
960
961
					if (!(rec_get_info_bits(rec2, comp)
962
					      & REC_INFO_MIN_REC_FLAG)) {
963
						ret = -1;
964
					}
965
966
					goto order_resolved;
967
968
				} else if (UNIV_UNLIKELY
969
					   (rec_get_info_bits(rec2, comp)
970
					    & REC_INFO_MIN_REC_FLAG)) {
971
972
					ret = 1;
973
974
					goto order_resolved;
975
				}
976
			}
977
978
			if (rec_offs_nth_extern(offsets1, cur_field)
979
			    || rec_offs_nth_extern(offsets2, cur_field)) {
980
				/* We do not compare to an externally
981
				stored field */
982
983
				goto order_resolved;
984
			}
985
986
			if (rec1_f_len == UNIV_SQL_NULL
987
			    || rec2_f_len == UNIV_SQL_NULL) {
988
989
				if (rec1_f_len == rec2_f_len) {
990
991
					goto next_field;
992
993
				} else if (rec2_f_len == UNIV_SQL_NULL) {
994
995
					/* We define the SQL null to be the
996
					smallest possible value of a field
997
					in the alphabetical order */
998
999
					ret = 1;
1000
				} else {
1001
					ret = -1;
1002
				}
1003
1004
				goto order_resolved;
1005
			}
1006
		}
1007
1008
		if (mtype >= DATA_FLOAT
1009
		    || (mtype == DATA_BLOB
1010
			&& 0 == (prtype & DATA_BINARY_TYPE)
1011
			&& dtype_get_charset_coll(prtype)
1012
			!= DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
1013
1014
			ret = cmp_whole_field(mtype, prtype,
1015
					      rec1_b_ptr,
1016
					      (unsigned) rec1_f_len,
1017
					      rec2_b_ptr,
1018
					      (unsigned) rec2_f_len);
1019
			if (ret != 0) {
1020
				cur_bytes = 0;
1021
1022
				goto order_resolved;
1023
			} else {
1024
				goto next_field;
1025
			}
1026
		}
1027
1028
		/* Set the pointers at the current byte */
1029
		rec1_b_ptr = rec1_b_ptr + cur_bytes;
1030
		rec2_b_ptr = rec2_b_ptr + cur_bytes;
1031
1032
		/* Compare then the fields */
1033
		for (;;) {
1034
			if (rec2_f_len <= cur_bytes) {
1035
1036
				if (rec1_f_len <= cur_bytes) {
1037
1038
					goto next_field;
1039
				}
1040
1041
				rec2_byte = dtype_get_pad_char(mtype, prtype);
1042
1043
				if (rec2_byte == ULINT_UNDEFINED) {
1044
					ret = 1;
1045
1046
					goto order_resolved;
1047
				}
1048
			} else {
1049
				rec2_byte = *rec2_b_ptr;
1050
			}
1051
1052
			if (rec1_f_len <= cur_bytes) {
1053
				rec1_byte = dtype_get_pad_char(mtype, prtype);
1054
1055
				if (rec1_byte == ULINT_UNDEFINED) {
1056
					ret = -1;
1057
1058
					goto order_resolved;
1059
				}
1060
			} else {
1061
				rec1_byte = *rec1_b_ptr;
1062
			}
1063
1064
			if (rec1_byte == rec2_byte) {
1065
				/* If the bytes are equal, they will remain
1066
				such even after the collation transformation
1067
				below */
1068
1069
				goto next_byte;
1070
			}
1071
1072
			if (mtype <= DATA_CHAR
1073
			    || (mtype == DATA_BLOB
1074
				&& !(prtype & DATA_BINARY_TYPE))) {
1075
1076
				rec1_byte = cmp_collate(rec1_byte);
1077
				rec2_byte = cmp_collate(rec2_byte);
1078
			}
1079
1080
			if (rec1_byte < rec2_byte) {
1081
				ret = -1;
1082
				goto order_resolved;
1083
			} else if (rec1_byte > rec2_byte) {
1084
				ret = 1;
1085
				goto order_resolved;
1086
			}
1087
next_byte:
1088
			/* Next byte */
1089
1090
			cur_bytes++;
1091
			rec1_b_ptr++;
1092
			rec2_b_ptr++;
1093
		}
1094
1095
next_field:
1096
		cur_field++;
1097
		cur_bytes = 0;
1098
	}
1099
1100
	ut_ad(cur_bytes == 0);
1101
1102
	/* If we ran out of fields, rec1 was equal to rec2 up
1103
	to the common fields */
1104
	ut_ad(ret == 0);
1105
order_resolved:
1106
1107
	ut_ad((ret >= - 1) && (ret <= 1));
1108
1109
	*matched_fields = cur_field;
1110
	*matched_bytes = cur_bytes;
1111
1112
	return(ret);
1113
#else /* !UNIV_HOTBACKUP */
1114
	/* This function depends on MySQL code that is not included in
1115
	InnoDB Hot Backup builds.  Besides, this function should never
1116
	be called in InnoDB Hot Backup. */
1117
	ut_error;
1118
	return(0);
1119
#endif /* !UNIV_HOTBACKUP */
1120
}
1121
1122
#ifdef UNIV_DEBUG
1123
/*****************************************************************
1124
Used in debug checking of cmp_dtuple_... .
1125
This function is used to compare a data tuple to a physical record. If
1126
dtuple has n fields then rec must have either m >= n fields, or it must
1127
differ from dtuple in some of the m fields rec has. If encounters an
1128
externally stored field, returns 0. */
1129
static
1130
int
1131
cmp_debug_dtuple_rec_with_match(
1132
/*============================*/
1133
				/* out: 1, 0, -1, if dtuple is greater, equal,
1134
				less than rec, respectively, when only the
1135
				common first fields are compared */
1136
	const dtuple_t*	dtuple,	/* in: data tuple */
1137
	const rec_t*	rec,	/* in: physical record which differs from
1138
				dtuple in some of the common fields, or which
1139
				has an equal number or more fields than
1140
				dtuple */
1141
	const ulint*	offsets,/* in: array returned by rec_get_offsets() */
1142
	ulint*		matched_fields) /* in/out: number of already
1143
				completely matched fields; when function
1144
				returns, contains the value for current
1145
				comparison */
1146
{
1147
	const dfield_t*	dtuple_field;	/* current field in logical record */
1148
	ulint		dtuple_f_len;	/* the length of the current field
1149
					in the logical record */
1150
	const byte*	dtuple_f_data;	/* pointer to the current logical
1151
					field data */
1152
	ulint		rec_f_len;	/* length of current field in rec */
1153
	const byte*	rec_f_data;	/* pointer to the current rec field */
1154
	int		ret = 3333;	/* return value */
1155
	ulint		cur_field;	/* current field number */
1156
1157
	ut_ad(dtuple && rec && matched_fields);
1158
	ut_ad(dtuple_check_typed(dtuple));
1159
	ut_ad(rec_offs_validate(rec, NULL, offsets));
1160
1161
	ut_ad(*matched_fields <= dtuple_get_n_fields_cmp(dtuple));
1162
	ut_ad(*matched_fields <= rec_offs_n_fields(offsets));
1163
1164
	cur_field = *matched_fields;
1165
1166
	if (cur_field == 0) {
1167
		if (UNIV_UNLIKELY
1168
		    (rec_get_info_bits(rec, rec_offs_comp(offsets))
1169
		     & REC_INFO_MIN_REC_FLAG)) {
1170
1171
			ret = !(dtuple_get_info_bits(dtuple)
1172
				& REC_INFO_MIN_REC_FLAG);
1173
1174
			goto order_resolved;
1175
		}
1176
1177
		if (UNIV_UNLIKELY
1178
		    (dtuple_get_info_bits(dtuple) & REC_INFO_MIN_REC_FLAG)) {
1179
			ret = -1;
1180
1181
			goto order_resolved;
1182
		}
1183
	}
1184
1185
	/* Match fields in a loop; stop if we run out of fields in dtuple */
1186
1187
	while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
1188
1189
		ulint	mtype;
1190
		ulint	prtype;
1191
1192
		dtuple_field = dtuple_get_nth_field(dtuple, cur_field);
1193
		{
1194
			const dtype_t*	type
1195
				= dfield_get_type(dtuple_field);
1196
1197
			mtype = type->mtype;
1198
			prtype = type->prtype;
1199
		}
1200
1201
		dtuple_f_data = dfield_get_data(dtuple_field);
1202
		dtuple_f_len = dfield_get_len(dtuple_field);
1203
1204
		rec_f_data = rec_get_nth_field(rec, offsets,
1205
					       cur_field, &rec_f_len);
1206
1207
		if (rec_offs_nth_extern(offsets, cur_field)) {
1208
			/* We do not compare to an externally stored field */
1209
1210
			ret = 0;
1211
1212
			goto order_resolved;
1213
		}
1214
1215
		ret = cmp_data_data(mtype, prtype, dtuple_f_data, dtuple_f_len,
1216
				    rec_f_data, rec_f_len);
1217
		if (ret != 0) {
1218
			goto order_resolved;
1219
		}
1220
1221
		cur_field++;
1222
	}
1223
1224
	ret = 0;	/* If we ran out of fields, dtuple was equal to rec
1225
			up to the common fields */
1226
order_resolved:
1227
	ut_ad((ret >= - 1) && (ret <= 1));
1228
1229
	*matched_fields = cur_field;
1230
1231
	return(ret);
1232
}
1233
#endif /* UNIV_DEBUG */