~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/row/row0row.c

  • Committer: Padraig O'Sullivan
  • Date: 2009-09-13 01:03:01 UTC
  • mto: (1126.9.2 captain-20090915-01)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: osullivan.padraig@gmail.com-20090913010301-tcvvezipx1124acy
Added calls to the dtrace delete begin/end probes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1996, 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
 
 
19
 
/**************************************************//**
20
 
@file row/row0row.c
21
 
General row routines
22
 
 
23
 
Created 4/20/1996 Heikki Tuuri
24
 
*******************************************************/
25
 
 
26
 
#include "row0row.h"
27
 
 
28
 
#ifdef UNIV_NONINL
29
 
#include "row0row.ic"
30
 
#endif
31
 
 
32
 
#include "data0type.h"
33
 
#include "dict0dict.h"
34
 
#include "btr0btr.h"
35
 
#include "ha_prototypes.h"
36
 
#include "mach0data.h"
37
 
#include "trx0rseg.h"
38
 
#include "trx0trx.h"
39
 
#include "trx0roll.h"
40
 
#include "trx0undo.h"
41
 
#include "trx0purge.h"
42
 
#include "trx0rec.h"
43
 
#include "que0que.h"
44
 
#include "row0ext.h"
45
 
#include "row0upd.h"
46
 
#include "rem0cmp.h"
47
 
#include "read0read.h"
48
 
#include "ut0mem.h"
49
 
 
50
 
/*********************************************************************//**
51
 
Gets the offset of trx id field, in bytes relative to the origin of
52
 
a clustered index record.
53
 
@return offset of DATA_TRX_ID */
54
 
UNIV_INTERN
55
 
ulint
56
 
row_get_trx_id_offset(
57
 
/*==================*/
58
 
        const rec_t*    rec __attribute__((unused)),
59
 
                                /*!< in: record */
60
 
        dict_index_t*   index,  /*!< in: clustered index */
61
 
        const ulint*    offsets)/*!< in: rec_get_offsets(rec, index) */
62
 
{
63
 
        ulint   pos;
64
 
        ulint   offset;
65
 
        ulint   len;
66
 
 
67
 
        ut_ad(dict_index_is_clust(index));
68
 
        ut_ad(rec_offs_validate(rec, index, offsets));
69
 
 
70
 
        pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
71
 
 
72
 
        offset = rec_get_nth_field_offs(offsets, pos, &len);
73
 
 
74
 
        ut_ad(len == DATA_TRX_ID_LEN);
75
 
 
76
 
        return(offset);
77
 
}
78
 
 
79
 
/*****************************************************************//**
80
 
When an insert or purge to a table is performed, this function builds
81
 
the entry to be inserted into or purged from an index on the table.
82
 
@return index entry which should be inserted or purged, or NULL if the
83
 
externally stored columns in the clustered index record are
84
 
unavailable and ext != NULL */
85
 
UNIV_INTERN
86
 
dtuple_t*
87
 
row_build_index_entry(
88
 
/*==================*/
89
 
        const dtuple_t* row,    /*!< in: row which should be
90
 
                                inserted or purged */
91
 
        row_ext_t*      ext,    /*!< in: externally stored column prefixes,
92
 
                                or NULL */
93
 
        dict_index_t*   index,  /*!< in: index on the table */
94
 
        mem_heap_t*     heap)   /*!< in: memory heap from which the memory for
95
 
                                the index entry is allocated */
96
 
{
97
 
        dtuple_t*       entry;
98
 
        ulint           entry_len;
99
 
        ulint           i;
100
 
 
101
 
        ut_ad(row && index && heap);
102
 
        ut_ad(dtuple_check_typed(row));
103
 
 
104
 
        entry_len = dict_index_get_n_fields(index);
105
 
        entry = dtuple_create(heap, entry_len);
106
 
 
107
 
        if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
108
 
                dtuple_set_n_fields_cmp(entry, entry_len);
109
 
                /* There may only be externally stored columns
110
 
                in a clustered index B-tree of a user table. */
111
 
                ut_a(!ext);
112
 
        } else {
113
 
                dtuple_set_n_fields_cmp(
114
 
                        entry, dict_index_get_n_unique_in_tree(index));
115
 
        }
116
 
 
117
 
        for (i = 0; i < entry_len; i++) {
118
 
                const dict_field_t*     ind_field
119
 
                        = dict_index_get_nth_field(index, i);
120
 
                const dict_col_t*       col
121
 
                        = ind_field->col;
122
 
                ulint                   col_no
123
 
                        = dict_col_get_no(col);
124
 
                dfield_t*               dfield
125
 
                        = dtuple_get_nth_field(entry, i);
126
 
                const dfield_t*         dfield2
127
 
                        = dtuple_get_nth_field(row, col_no);
128
 
                ulint                   len
129
 
                        = dfield_get_len(dfield2);
130
 
 
131
 
                dfield_copy(dfield, dfield2);
132
 
 
133
 
                if (dfield_is_null(dfield) || ind_field->prefix_len == 0) {
134
 
                        continue;
135
 
                }
136
 
 
137
 
                /* If a column prefix index, take only the prefix.
138
 
                Prefix-indexed columns may be externally stored. */
139
 
                ut_ad(col->ord_part);
140
 
 
141
 
                if (UNIV_LIKELY_NULL(ext)) {
142
 
                        /* See if the column is stored externally. */
143
 
                        const byte*     buf = row_ext_lookup(ext, col_no,
144
 
                                                             &len);
145
 
                        if (UNIV_LIKELY_NULL(buf)) {
146
 
                                if (UNIV_UNLIKELY(buf == field_ref_zero)) {
147
 
                                        return(NULL);
148
 
                                }
149
 
                                dfield_set_data(dfield, buf, len);
150
 
                        }
151
 
                } else if (dfield_is_ext(dfield)) {
152
 
                        ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
153
 
                        len -= BTR_EXTERN_FIELD_REF_SIZE;
154
 
                        ut_a(ind_field->prefix_len <= len
155
 
                             || dict_index_is_clust(index));
156
 
                }
157
 
 
158
 
                len = dtype_get_at_most_n_mbchars(
159
 
                        col->prtype, col->mbminlen, col->mbmaxlen,
160
 
                        ind_field->prefix_len, len, dfield_get_data(dfield));
161
 
                dfield_set_len(dfield, len);
162
 
        }
163
 
 
164
 
        ut_ad(dtuple_check_typed(entry));
165
 
 
166
 
        return(entry);
167
 
}
168
 
 
169
 
/*******************************************************************//**
170
 
An inverse function to row_build_index_entry. Builds a row from a
171
 
record in a clustered index.
172
 
@return own: row built; see the NOTE below! */
173
 
UNIV_INTERN
174
 
dtuple_t*
175
 
row_build(
176
 
/*======*/
177
 
        ulint                   type,   /*!< in: ROW_COPY_POINTERS or
178
 
                                        ROW_COPY_DATA; the latter
179
 
                                        copies also the data fields to
180
 
                                        heap while the first only
181
 
                                        places pointers to data fields
182
 
                                        on the index page, and thus is
183
 
                                        more efficient */
184
 
        const dict_index_t*     index,  /*!< in: clustered index */
185
 
        const rec_t*            rec,    /*!< in: record in the clustered
186
 
                                        index; NOTE: in the case
187
 
                                        ROW_COPY_POINTERS the data
188
 
                                        fields in the row will point
189
 
                                        directly into this record,
190
 
                                        therefore, the buffer page of
191
 
                                        this record must be at least
192
 
                                        s-latched and the latch held
193
 
                                        as long as the row dtuple is used! */
194
 
        const ulint*            offsets,/*!< in: rec_get_offsets(rec,index)
195
 
                                        or NULL, in which case this function
196
 
                                        will invoke rec_get_offsets() */
197
 
        const dict_table_t*     col_table,
198
 
                                        /*!< in: table, to check which
199
 
                                        externally stored columns
200
 
                                        occur in the ordering columns
201
 
                                        of an index, or NULL if
202
 
                                        index->table should be
203
 
                                        consulted instead */
204
 
        row_ext_t**             ext,    /*!< out, own: cache of
205
 
                                        externally stored column
206
 
                                        prefixes, or NULL */
207
 
        mem_heap_t*             heap)   /*!< in: memory heap from which
208
 
                                        the memory needed is allocated */
209
 
{
210
 
        dtuple_t*               row;
211
 
        const dict_table_t*     table;
212
 
        ulint                   n_fields;
213
 
        ulint                   n_ext_cols;
214
 
        ulint*                  ext_cols        = NULL; /* remove warning */
215
 
        ulint                   len;
216
 
        ulint                   row_len;
217
 
        byte*                   buf;
218
 
        ulint                   i;
219
 
        ulint                   j;
220
 
        mem_heap_t*             tmp_heap        = NULL;
221
 
        ulint                   offsets_[REC_OFFS_NORMAL_SIZE];
222
 
        rec_offs_init(offsets_);
223
 
 
224
 
        ut_ad(index && rec && heap);
225
 
        ut_ad(dict_index_is_clust(index));
226
 
 
227
 
        if (!offsets) {
228
 
                offsets = rec_get_offsets(rec, index, offsets_,
229
 
                                          ULINT_UNDEFINED, &tmp_heap);
230
 
        } else {
231
 
                ut_ad(rec_offs_validate(rec, index, offsets));
232
 
        }
233
 
 
234
 
        if (type != ROW_COPY_POINTERS) {
235
 
                /* Take a copy of rec to heap */
236
 
                buf = mem_heap_alloc(heap, rec_offs_size(offsets));
237
 
                rec = rec_copy(buf, rec, offsets);
238
 
                /* Avoid a debug assertion in rec_offs_validate(). */
239
 
                rec_offs_make_valid(rec, index, (ulint*) offsets);
240
 
        }
241
 
 
242
 
        table = index->table;
243
 
        row_len = dict_table_get_n_cols(table);
244
 
 
245
 
        row = dtuple_create(heap, row_len);
246
 
 
247
 
        dict_table_copy_types(row, table);
248
 
 
249
 
        dtuple_set_info_bits(row, rec_get_info_bits(
250
 
                                     rec, dict_table_is_comp(table)));
251
 
 
252
 
        n_fields = rec_offs_n_fields(offsets);
253
 
        n_ext_cols = rec_offs_n_extern(offsets);
254
 
        if (n_ext_cols) {
255
 
                ext_cols = mem_heap_alloc(heap, n_ext_cols * sizeof *ext_cols);
256
 
        }
257
 
 
258
 
        for (i = j = 0; i < n_fields; i++) {
259
 
                dict_field_t*           ind_field
260
 
                        = dict_index_get_nth_field(index, i);
261
 
                const dict_col_t*       col
262
 
                        = dict_field_get_col(ind_field);
263
 
                ulint                   col_no
264
 
                        = dict_col_get_no(col);
265
 
                dfield_t*               dfield
266
 
                        = dtuple_get_nth_field(row, col_no);
267
 
 
268
 
                if (ind_field->prefix_len == 0) {
269
 
 
270
 
                        const byte*     field = rec_get_nth_field(
271
 
                                rec, offsets, i, &len);
272
 
 
273
 
                        dfield_set_data(dfield, field, len);
274
 
                }
275
 
 
276
 
                if (rec_offs_nth_extern(offsets, i)) {
277
 
                        dfield_set_ext(dfield);
278
 
 
279
 
                        if (UNIV_LIKELY_NULL(col_table)) {
280
 
                                ut_a(col_no
281
 
                                     < dict_table_get_n_cols(col_table));
282
 
                                col = dict_table_get_nth_col(
283
 
                                        col_table, col_no);
284
 
                        }
285
 
 
286
 
                        if (col->ord_part) {
287
 
                                /* We will have to fetch prefixes of
288
 
                                externally stored columns that are
289
 
                                referenced by column prefixes. */
290
 
                                ext_cols[j++] = col_no;
291
 
                        }
292
 
                }
293
 
        }
294
 
 
295
 
        ut_ad(dtuple_check_typed(row));
296
 
 
297
 
        if (j) {
298
 
                *ext = row_ext_create(j, ext_cols, row,
299
 
                                      dict_table_zip_size(index->table),
300
 
                                      heap);
301
 
        } else {
302
 
                *ext = NULL;
303
 
        }
304
 
 
305
 
        if (tmp_heap) {
306
 
                mem_heap_free(tmp_heap);
307
 
        }
308
 
 
309
 
        return(row);
310
 
}
311
 
 
312
 
/*******************************************************************//**
313
 
Converts an index record to a typed data tuple.
314
 
@return index entry built; does not set info_bits, and the data fields
315
 
in the entry will point directly to rec */
316
 
UNIV_INTERN
317
 
dtuple_t*
318
 
row_rec_to_index_entry_low(
319
 
/*=======================*/
320
 
        const rec_t*            rec,    /*!< in: record in the index */
321
 
        const dict_index_t*     index,  /*!< in: index */
322
 
        const ulint*            offsets,/*!< in: rec_get_offsets(rec, index) */
323
 
        ulint*                  n_ext,  /*!< out: number of externally
324
 
                                        stored columns */
325
 
        mem_heap_t*             heap)   /*!< in: memory heap from which
326
 
                                        the memory needed is allocated */
327
 
{
328
 
        dtuple_t*       entry;
329
 
        dfield_t*       dfield;
330
 
        ulint           i;
331
 
        const byte*     field;
332
 
        ulint           len;
333
 
        ulint           rec_len;
334
 
 
335
 
        ut_ad(rec && heap && index);
336
 
        /* Because this function may be invoked by row0merge.c
337
 
        on a record whose header is in different format, the check
338
 
        rec_offs_validate(rec, index, offsets) must be avoided here. */
339
 
        ut_ad(n_ext);
340
 
        *n_ext = 0;
341
 
 
342
 
        rec_len = rec_offs_n_fields(offsets);
343
 
 
344
 
        entry = dtuple_create(heap, rec_len);
345
 
 
346
 
        dtuple_set_n_fields_cmp(entry,
347
 
                                dict_index_get_n_unique_in_tree(index));
348
 
        ut_ad(rec_len == dict_index_get_n_fields(index));
349
 
 
350
 
        dict_index_copy_types(entry, index, rec_len);
351
 
 
352
 
        for (i = 0; i < rec_len; i++) {
353
 
 
354
 
                dfield = dtuple_get_nth_field(entry, i);
355
 
                field = rec_get_nth_field(rec, offsets, i, &len);
356
 
 
357
 
                dfield_set_data(dfield, field, len);
358
 
 
359
 
                if (rec_offs_nth_extern(offsets, i)) {
360
 
                        dfield_set_ext(dfield);
361
 
                        (*n_ext)++;
362
 
                }
363
 
        }
364
 
 
365
 
        ut_ad(dtuple_check_typed(entry));
366
 
 
367
 
        return(entry);
368
 
}
369
 
 
370
 
/*******************************************************************//**
371
 
Converts an index record to a typed data tuple. NOTE that externally
372
 
stored (often big) fields are NOT copied to heap.
373
 
@return own: index entry built; see the NOTE below! */
374
 
UNIV_INTERN
375
 
dtuple_t*
376
 
row_rec_to_index_entry(
377
 
/*===================*/
378
 
        ulint                   type,   /*!< in: ROW_COPY_DATA, or
379
 
                                        ROW_COPY_POINTERS: the former
380
 
                                        copies also the data fields to
381
 
                                        heap as the latter only places
382
 
                                        pointers to data fields on the
383
 
                                        index page */
384
 
        const rec_t*            rec,    /*!< in: record in the index;
385
 
                                        NOTE: in the case
386
 
                                        ROW_COPY_POINTERS the data
387
 
                                        fields in the row will point
388
 
                                        directly into this record,
389
 
                                        therefore, the buffer page of
390
 
                                        this record must be at least
391
 
                                        s-latched and the latch held
392
 
                                        as long as the dtuple is used! */
393
 
        const dict_index_t*     index,  /*!< in: index */
394
 
        ulint*                  offsets,/*!< in/out: rec_get_offsets(rec) */
395
 
        ulint*                  n_ext,  /*!< out: number of externally
396
 
                                        stored columns */
397
 
        mem_heap_t*             heap)   /*!< in: memory heap from which
398
 
                                        the memory needed is allocated */
399
 
{
400
 
        dtuple_t*       entry;
401
 
        byte*           buf;
402
 
 
403
 
        ut_ad(rec && heap && index);
404
 
        ut_ad(rec_offs_validate(rec, index, offsets));
405
 
 
406
 
        if (type == ROW_COPY_DATA) {
407
 
                /* Take a copy of rec to heap */
408
 
                buf = mem_heap_alloc(heap, rec_offs_size(offsets));
409
 
                rec = rec_copy(buf, rec, offsets);
410
 
                /* Avoid a debug assertion in rec_offs_validate(). */
411
 
                rec_offs_make_valid(rec, index, offsets);
412
 
        }
413
 
 
414
 
        entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap);
415
 
 
416
 
        dtuple_set_info_bits(entry,
417
 
                             rec_get_info_bits(rec, rec_offs_comp(offsets)));
418
 
 
419
 
        return(entry);
420
 
}
421
 
 
422
 
/*******************************************************************//**
423
 
Builds from a secondary index record a row reference with which we can
424
 
search the clustered index record.
425
 
@return own: row reference built; see the NOTE below! */
426
 
UNIV_INTERN
427
 
dtuple_t*
428
 
row_build_row_ref(
429
 
/*==============*/
430
 
        ulint           type,   /*!< in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
431
 
                                the former copies also the data fields to
432
 
                                heap, whereas the latter only places pointers
433
 
                                to data fields on the index page */
434
 
        dict_index_t*   index,  /*!< in: secondary index */
435
 
        const rec_t*    rec,    /*!< in: record in the index;
436
 
                                NOTE: in the case ROW_COPY_POINTERS
437
 
                                the data fields in the row will point
438
 
                                directly into this record, therefore,
439
 
                                the buffer page of this record must be
440
 
                                at least s-latched and the latch held
441
 
                                as long as the row reference is used! */
442
 
        mem_heap_t*     heap)   /*!< in: memory heap from which the memory
443
 
                                needed is allocated */
444
 
{
445
 
        dict_table_t*   table;
446
 
        dict_index_t*   clust_index;
447
 
        dfield_t*       dfield;
448
 
        dtuple_t*       ref;
449
 
        const byte*     field;
450
 
        ulint           len;
451
 
        ulint           ref_len;
452
 
        ulint           pos;
453
 
        byte*           buf;
454
 
        ulint           clust_col_prefix_len;
455
 
        ulint           i;
456
 
        mem_heap_t*     tmp_heap        = NULL;
457
 
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
458
 
        ulint*          offsets         = offsets_;
459
 
        rec_offs_init(offsets_);
460
 
 
461
 
        ut_ad(index && rec && heap);
462
 
        ut_ad(!dict_index_is_clust(index));
463
 
 
464
 
        offsets = rec_get_offsets(rec, index, offsets,
465
 
                                  ULINT_UNDEFINED, &tmp_heap);
466
 
        /* Secondary indexes must not contain externally stored columns. */
467
 
        ut_ad(!rec_offs_any_extern(offsets));
468
 
 
469
 
        if (type == ROW_COPY_DATA) {
470
 
                /* Take a copy of rec to heap */
471
 
 
472
 
                buf = mem_heap_alloc(heap, rec_offs_size(offsets));
473
 
 
474
 
                rec = rec_copy(buf, rec, offsets);
475
 
                /* Avoid a debug assertion in rec_offs_validate(). */
476
 
                rec_offs_make_valid(rec, index, offsets);
477
 
        }
478
 
 
479
 
        table = index->table;
480
 
 
481
 
        clust_index = dict_table_get_first_index(table);
482
 
 
483
 
        ref_len = dict_index_get_n_unique(clust_index);
484
 
 
485
 
        ref = dtuple_create(heap, ref_len);
486
 
 
487
 
        dict_index_copy_types(ref, clust_index, ref_len);
488
 
 
489
 
        for (i = 0; i < ref_len; i++) {
490
 
                dfield = dtuple_get_nth_field(ref, i);
491
 
 
492
 
                pos = dict_index_get_nth_field_pos(index, clust_index, i);
493
 
 
494
 
                ut_a(pos != ULINT_UNDEFINED);
495
 
 
496
 
                field = rec_get_nth_field(rec, offsets, pos, &len);
497
 
 
498
 
                dfield_set_data(dfield, field, len);
499
 
 
500
 
                /* If the primary key contains a column prefix, then the
501
 
                secondary index may contain a longer prefix of the same
502
 
                column, or the full column, and we must adjust the length
503
 
                accordingly. */
504
 
 
505
 
                clust_col_prefix_len = dict_index_get_nth_field(
506
 
                        clust_index, i)->prefix_len;
507
 
 
508
 
                if (clust_col_prefix_len > 0) {
509
 
                        if (len != UNIV_SQL_NULL) {
510
 
 
511
 
                                const dtype_t*  dtype
512
 
                                        = dfield_get_type(dfield);
513
 
 
514
 
                                dfield_set_len(dfield,
515
 
                                               dtype_get_at_most_n_mbchars(
516
 
                                                       dtype->prtype,
517
 
                                                       dtype->mbminlen,
518
 
                                                       dtype->mbmaxlen,
519
 
                                                       clust_col_prefix_len,
520
 
                                                       len, (char*) field));
521
 
                        }
522
 
                }
523
 
        }
524
 
 
525
 
        ut_ad(dtuple_check_typed(ref));
526
 
        if (tmp_heap) {
527
 
                mem_heap_free(tmp_heap);
528
 
        }
529
 
 
530
 
        return(ref);
531
 
}
532
 
 
533
 
/*******************************************************************//**
534
 
Builds from a secondary index record a row reference with which we can
535
 
search the clustered index record. */
536
 
UNIV_INTERN
537
 
void
538
 
row_build_row_ref_in_tuple(
539
 
/*=======================*/
540
 
        dtuple_t*               ref,    /*!< in/out: row reference built;
541
 
                                        see the NOTE below! */
542
 
        const rec_t*            rec,    /*!< in: record in the index;
543
 
                                        NOTE: the data fields in ref
544
 
                                        will point directly into this
545
 
                                        record, therefore, the buffer
546
 
                                        page of this record must be at
547
 
                                        least s-latched and the latch
548
 
                                        held as long as the row
549
 
                                        reference is used! */
550
 
        const dict_index_t*     index,  /*!< in: secondary index */
551
 
        ulint*                  offsets,/*!< in: rec_get_offsets(rec, index)
552
 
                                        or NULL */
553
 
        trx_t*                  trx)    /*!< in: transaction */
554
 
{
555
 
        const dict_index_t*     clust_index;
556
 
        dfield_t*               dfield;
557
 
        const byte*             field;
558
 
        ulint                   len;
559
 
        ulint                   ref_len;
560
 
        ulint                   pos;
561
 
        ulint                   clust_col_prefix_len;
562
 
        ulint                   i;
563
 
        mem_heap_t*             heap            = NULL;
564
 
        ulint                   offsets_[REC_OFFS_NORMAL_SIZE];
565
 
        rec_offs_init(offsets_);
566
 
 
567
 
        ut_a(ref);
568
 
        ut_a(index);
569
 
        ut_a(rec);
570
 
        ut_ad(!dict_index_is_clust(index));
571
 
 
572
 
        if (UNIV_UNLIKELY(!index->table)) {
573
 
                fputs("InnoDB: table ", stderr);
574
 
notfound:
575
 
                ut_print_name(stderr, trx, TRUE, index->table_name);
576
 
                fputs(" for index ", stderr);
577
 
                ut_print_name(stderr, trx, FALSE, index->name);
578
 
                fputs(" not found\n", stderr);
579
 
                ut_error;
580
 
        }
581
 
 
582
 
        clust_index = dict_table_get_first_index(index->table);
583
 
 
584
 
        if (UNIV_UNLIKELY(!clust_index)) {
585
 
                fputs("InnoDB: clust index for table ", stderr);
586
 
                goto notfound;
587
 
        }
588
 
 
589
 
        if (!offsets) {
590
 
                offsets = rec_get_offsets(rec, index, offsets_,
591
 
                                          ULINT_UNDEFINED, &heap);
592
 
        } else {
593
 
                ut_ad(rec_offs_validate(rec, index, offsets));
594
 
        }
595
 
 
596
 
        /* Secondary indexes must not contain externally stored columns. */
597
 
        ut_ad(!rec_offs_any_extern(offsets));
598
 
        ref_len = dict_index_get_n_unique(clust_index);
599
 
 
600
 
        ut_ad(ref_len == dtuple_get_n_fields(ref));
601
 
 
602
 
        dict_index_copy_types(ref, clust_index, ref_len);
603
 
 
604
 
        for (i = 0; i < ref_len; i++) {
605
 
                dfield = dtuple_get_nth_field(ref, i);
606
 
 
607
 
                pos = dict_index_get_nth_field_pos(index, clust_index, i);
608
 
 
609
 
                ut_a(pos != ULINT_UNDEFINED);
610
 
 
611
 
                field = rec_get_nth_field(rec, offsets, pos, &len);
612
 
 
613
 
                dfield_set_data(dfield, field, len);
614
 
 
615
 
                /* If the primary key contains a column prefix, then the
616
 
                secondary index may contain a longer prefix of the same
617
 
                column, or the full column, and we must adjust the length
618
 
                accordingly. */
619
 
 
620
 
                clust_col_prefix_len = dict_index_get_nth_field(
621
 
                        clust_index, i)->prefix_len;
622
 
 
623
 
                if (clust_col_prefix_len > 0) {
624
 
                        if (len != UNIV_SQL_NULL) {
625
 
 
626
 
                                const dtype_t*  dtype
627
 
                                        = dfield_get_type(dfield);
628
 
 
629
 
                                dfield_set_len(dfield,
630
 
                                               dtype_get_at_most_n_mbchars(
631
 
                                                       dtype->prtype,
632
 
                                                       dtype->mbminlen,
633
 
                                                       dtype->mbmaxlen,
634
 
                                                       clust_col_prefix_len,
635
 
                                                       len, (char*) field));
636
 
                        }
637
 
                }
638
 
        }
639
 
 
640
 
        ut_ad(dtuple_check_typed(ref));
641
 
        if (UNIV_LIKELY_NULL(heap)) {
642
 
                mem_heap_free(heap);
643
 
        }
644
 
}
645
 
 
646
 
/***************************************************************//**
647
 
Searches the clustered index record for a row, if we have the row reference.
648
 
@return TRUE if found */
649
 
UNIV_INTERN
650
 
ibool
651
 
row_search_on_row_ref(
652
 
/*==================*/
653
 
        btr_pcur_t*             pcur,   /*!< out: persistent cursor, which must
654
 
                                        be closed by the caller */
655
 
        ulint                   mode,   /*!< in: BTR_MODIFY_LEAF, ... */
656
 
        const dict_table_t*     table,  /*!< in: table */
657
 
        const dtuple_t*         ref,    /*!< in: row reference */
658
 
        mtr_t*                  mtr)    /*!< in/out: mtr */
659
 
{
660
 
        ulint           low_match;
661
 
        rec_t*          rec;
662
 
        dict_index_t*   index;
663
 
 
664
 
        ut_ad(dtuple_check_typed(ref));
665
 
 
666
 
        index = dict_table_get_first_index(table);
667
 
 
668
 
        ut_a(dtuple_get_n_fields(ref) == dict_index_get_n_unique(index));
669
 
 
670
 
        btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr);
671
 
 
672
 
        low_match = btr_pcur_get_low_match(pcur);
673
 
 
674
 
        rec = btr_pcur_get_rec(pcur);
675
 
 
676
 
        if (page_rec_is_infimum(rec)) {
677
 
 
678
 
                return(FALSE);
679
 
        }
680
 
 
681
 
        if (low_match != dtuple_get_n_fields(ref)) {
682
 
 
683
 
                return(FALSE);
684
 
        }
685
 
 
686
 
        return(TRUE);
687
 
}
688
 
 
689
 
/*********************************************************************//**
690
 
Fetches the clustered index record for a secondary index record. The latches
691
 
on the secondary index record are preserved.
692
 
@return record or NULL, if no record found */
693
 
UNIV_INTERN
694
 
rec_t*
695
 
row_get_clust_rec(
696
 
/*==============*/
697
 
        ulint           mode,   /*!< in: BTR_MODIFY_LEAF, ... */
698
 
        const rec_t*    rec,    /*!< in: record in a secondary index */
699
 
        dict_index_t*   index,  /*!< in: secondary index */
700
 
        dict_index_t**  clust_index,/*!< out: clustered index */
701
 
        mtr_t*          mtr)    /*!< in: mtr */
702
 
{
703
 
        mem_heap_t*     heap;
704
 
        dtuple_t*       ref;
705
 
        dict_table_t*   table;
706
 
        btr_pcur_t      pcur;
707
 
        ibool           found;
708
 
        rec_t*          clust_rec;
709
 
 
710
 
        ut_ad(!dict_index_is_clust(index));
711
 
 
712
 
        table = index->table;
713
 
 
714
 
        heap = mem_heap_create(256);
715
 
 
716
 
        ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
717
 
 
718
 
        found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
719
 
 
720
 
        clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
721
 
 
722
 
        mem_heap_free(heap);
723
 
 
724
 
        btr_pcur_close(&pcur);
725
 
 
726
 
        *clust_index = dict_table_get_first_index(table);
727
 
 
728
 
        return(clust_rec);
729
 
}
730
 
 
731
 
/***************************************************************//**
732
 
Searches an index record.
733
 
@return TRUE if found */
734
 
UNIV_INTERN
735
 
ibool
736
 
row_search_index_entry(
737
 
/*===================*/
738
 
        dict_index_t*   index,  /*!< in: index */
739
 
        const dtuple_t* entry,  /*!< in: index entry */
740
 
        ulint           mode,   /*!< in: BTR_MODIFY_LEAF, ... */
741
 
        btr_pcur_t*     pcur,   /*!< in/out: persistent cursor, which must
742
 
                                be closed by the caller */
743
 
        mtr_t*          mtr)    /*!< in: mtr */
744
 
{
745
 
        ulint   n_fields;
746
 
        ulint   low_match;
747
 
        rec_t*  rec;
748
 
 
749
 
        ut_ad(dtuple_check_typed(entry));
750
 
 
751
 
        btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
752
 
        low_match = btr_pcur_get_low_match(pcur);
753
 
 
754
 
        rec = btr_pcur_get_rec(pcur);
755
 
 
756
 
        n_fields = dtuple_get_n_fields(entry);
757
 
 
758
 
        return(!page_rec_is_infimum(rec) && low_match == n_fields);
759
 
}
760
 
 
761
 
#if !defined(BUILD_DRIZZLE)
762
 
# include "my_sys.h"
763
 
#endif
764
 
 
765
 
 
766
 
/*******************************************************************//**
767
 
Formats the raw data in "data" (in InnoDB on-disk format) that is of
768
 
type DATA_INT using "prtype" and writes the result to "buf".
769
 
If the data is in unknown format, then nothing is written to "buf",
770
 
0 is returned and "format_in_hex" is set to TRUE, otherwise
771
 
"format_in_hex" is left untouched.
772
 
Not more than "buf_size" bytes are written to "buf".
773
 
The result is always '\0'-terminated (provided buf_size > 0) and the
774
 
number of bytes that were written to "buf" is returned (including the
775
 
terminating '\0').
776
 
@return number of bytes that were written */
777
 
static
778
 
ulint
779
 
row_raw_format_int(
780
 
/*===============*/
781
 
        const char*     data,           /*!< in: raw data */
782
 
        ulint           data_len,       /*!< in: raw data length
783
 
                                        in bytes */
784
 
        ulint           prtype,         /*!< in: precise type */
785
 
        char*           buf,            /*!< out: output buffer */
786
 
        ulint           buf_size,       /*!< in: output buffer size
787
 
                                        in bytes */
788
 
        ibool*          format_in_hex)  /*!< out: should the data be
789
 
                                        formated in hex */
790
 
{
791
 
        ulint   ret;
792
 
 
793
 
        if (data_len <= sizeof(ullint)) {
794
 
 
795
 
                ullint          value;
796
 
                ibool           unsigned_type = prtype & DATA_UNSIGNED;
797
 
 
798
 
                value = mach_read_int_type((const byte*) data,
799
 
                                           data_len, unsigned_type);
800
 
 
801
 
                if (unsigned_type) {
802
 
 
803
 
                        ret = ut_snprintf(buf, buf_size, "%llu",
804
 
                                          value) + 1;
805
 
                } else {
806
 
 
807
 
                        ret = ut_snprintf(buf, buf_size, "%lld",
808
 
                                          (long long) value) + 1;
809
 
                }
810
 
 
811
 
        } else {
812
 
 
813
 
                *format_in_hex = TRUE;
814
 
                ret = 0;
815
 
        }
816
 
 
817
 
        return(ut_min(ret, buf_size));
818
 
}
819
 
 
820
 
/*******************************************************************//**
821
 
Formats the raw data in "data" (in InnoDB on-disk format) that is of
822
 
type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "prtype" and writes the
823
 
result to "buf".
824
 
If the data is in binary format, then nothing is written to "buf",
825
 
0 is returned and "format_in_hex" is set to TRUE, otherwise
826
 
"format_in_hex" is left untouched.
827
 
Not more than "buf_size" bytes are written to "buf".
828
 
The result is always '\0'-terminated (provided buf_size > 0) and the
829
 
number of bytes that were written to "buf" is returned (including the
830
 
terminating '\0').
831
 
@return number of bytes that were written */
832
 
static
833
 
ulint
834
 
row_raw_format_str(
835
 
/*===============*/
836
 
        const char*     data,           /*!< in: raw data */
837
 
        ulint           data_len,       /*!< in: raw data length
838
 
                                        in bytes */
839
 
        ulint           prtype,         /*!< in: precise type */
840
 
        char*           buf,            /*!< out: output buffer */
841
 
        ulint           buf_size,       /*!< in: output buffer size
842
 
                                        in bytes */
843
 
        ibool*          format_in_hex)  /*!< out: should the data be
844
 
                                        formated in hex */
845
 
{
846
 
        ulint   charset_coll;
847
 
 
848
 
        if (buf_size == 0) {
849
 
 
850
 
                return(0);
851
 
        }
852
 
 
853
 
        /* we assume system_charset_info is UTF-8 */
854
 
 
855
 
        charset_coll = dtype_get_charset_coll(prtype);
856
 
 
857
 
        if (UNIV_LIKELY(dtype_is_utf8(prtype))) {
858
 
 
859
 
                return(ut_str_sql_format(data, data_len, buf, buf_size));
860
 
        }
861
 
        /* else */
862
 
 
863
 
        if (charset_coll == DATA_MYSQL_BINARY_CHARSET_COLL) {
864
 
 
865
 
                *format_in_hex = TRUE;
866
 
                return(0);
867
 
        }
868
 
        /* else */
869
 
 
870
 
        return(innobase_raw_format(data, data_len, charset_coll,
871
 
                                          buf, buf_size));
872
 
}
873
 
 
874
 
/*******************************************************************//**
875
 
Formats the raw data in "data" (in InnoDB on-disk format) using
876
 
"dict_field" and writes the result to "buf".
877
 
Not more than "buf_size" bytes are written to "buf".
878
 
The result is always NUL-terminated (provided buf_size is positive) and the
879
 
number of bytes that were written to "buf" is returned (including the
880
 
terminating NUL).
881
 
@return number of bytes that were written */
882
 
UNIV_INTERN
883
 
ulint
884
 
row_raw_format(
885
 
/*===========*/
886
 
        const char*             data,           /*!< in: raw data */
887
 
        ulint                   data_len,       /*!< in: raw data length
888
 
                                                in bytes */
889
 
        const dict_field_t*     dict_field,     /*!< in: index field */
890
 
        char*                   buf,            /*!< out: output buffer */
891
 
        ulint                   buf_size)       /*!< in: output buffer size
892
 
                                                in bytes */
893
 
{
894
 
        ulint   mtype;
895
 
        ulint   prtype;
896
 
        ulint   ret= 0;
897
 
        ibool   format_in_hex;
898
 
 
899
 
        if (buf_size == 0) {
900
 
 
901
 
                return(ret);
902
 
        }
903
 
 
904
 
        if (data_len == UNIV_SQL_NULL) {
905
 
 
906
 
                ret = ut_snprintf((char*) buf, buf_size, "NULL") + 1;
907
 
 
908
 
                return(ut_min(ret, buf_size));
909
 
        }
910
 
 
911
 
        mtype = dict_field->col->mtype;
912
 
        prtype = dict_field->col->prtype;
913
 
 
914
 
        format_in_hex = FALSE;
915
 
 
916
 
        switch (mtype) {
917
 
        case DATA_INT:
918
 
 
919
 
                ret = row_raw_format_int(data, data_len, prtype,
920
 
                                         buf, buf_size, &format_in_hex);
921
 
                break;
922
 
        case DATA_CHAR:
923
 
        case DATA_VARCHAR:
924
 
        case DATA_MYSQL:
925
 
        case DATA_VARMYSQL:
926
 
 
927
 
                ret = row_raw_format_str(data, data_len, prtype,
928
 
                                         buf, buf_size, &format_in_hex);
929
 
                break;
930
 
        /* XXX support more data types */
931
 
        default:
932
 
 
933
 
                format_in_hex = TRUE;
934
 
        }
935
 
 
936
 
        if (format_in_hex) {
937
 
 
938
 
                if (UNIV_LIKELY(buf_size > 2)) {
939
 
 
940
 
                        memcpy(buf, "0x", 2);
941
 
                        buf += 2;
942
 
                        buf_size -= 2;
943
 
                        ret = 2 + ut_raw_to_hex(data, data_len,
944
 
                                                buf, buf_size);
945
 
                } else {
946
 
 
947
 
                        buf[0] = '\0';
948
 
                        ret = 1;
949
 
                }
950
 
        }
951
 
 
952
 
        return(ret);
953
 
}
954
 
 
955
 
#ifdef UNIV_COMPILE_TEST_FUNCS
956
 
 
957
 
#include "ut0dbg.h"
958
 
 
959
 
void
960
 
test_row_raw_format_int()
961
 
{
962
 
        ulint   ret;
963
 
        char    buf[128];
964
 
        ibool   format_in_hex;
965
 
 
966
 
#define CALL_AND_TEST(data, data_len, prtype, buf, buf_size,\
967
 
                      ret_expected, buf_expected, format_in_hex_expected)\
968
 
        do {\
969
 
                ibool   ok = TRUE;\
970
 
                ulint   i;\
971
 
                memset(buf, 'x', 10);\
972
 
                buf[10] = '\0';\
973
 
                format_in_hex = FALSE;\
974
 
                fprintf(stderr, "TESTING \"\\x");\
975
 
                for (i = 0; i < data_len; i++) {\
976
 
                        fprintf(stderr, "%02hhX", data[i]);\
977
 
                }\
978
 
                fprintf(stderr, "\", %lu, %lu, %lu\n",\
979
 
                        (ulint) data_len, (ulint) prtype,\
980
 
                        (ulint) buf_size);\
981
 
                ret = row_raw_format_int(data, data_len, prtype,\
982
 
                                         buf, buf_size, &format_in_hex);\
983
 
                if (ret != ret_expected) {\
984
 
                        fprintf(stderr, "expected ret %lu, got %lu\n",\
985
 
                                (ulint) ret_expected, ret);\
986
 
                        ok = FALSE;\
987
 
                }\
988
 
                if (strcmp((char*) buf, buf_expected) != 0) {\
989
 
                        fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
990
 
                                buf_expected, buf);\
991
 
                        ok = FALSE;\
992
 
                }\
993
 
                if (format_in_hex != format_in_hex_expected) {\
994
 
                        fprintf(stderr, "expected format_in_hex %d, got %d\n",\
995
 
                                (int) format_in_hex_expected,\
996
 
                                (int) format_in_hex);\
997
 
                        ok = FALSE;\
998
 
                }\
999
 
                if (ok) {\
1000
 
                        fprintf(stderr, "OK: %lu, \"%s\" %d\n\n",\
1001
 
                                (ulint) ret, buf, (int) format_in_hex);\
1002
 
                } else {\
1003
 
                        return;\
1004
 
                }\
1005
 
        } while (0)
1006
 
 
1007
 
#if 1
1008
 
        /* min values for signed 1-8 byte integers */
1009
 
 
1010
 
        CALL_AND_TEST("\x00", 1, 0,
1011
 
                      buf, sizeof(buf), 5, "-128", 0);
1012
 
 
1013
 
        CALL_AND_TEST("\x00\x00", 2, 0,
1014
 
                      buf, sizeof(buf), 7, "-32768", 0);
1015
 
 
1016
 
        CALL_AND_TEST("\x00\x00\x00", 3, 0,
1017
 
                      buf, sizeof(buf), 9, "-8388608", 0);
1018
 
 
1019
 
        CALL_AND_TEST("\x00\x00\x00\x00", 4, 0,
1020
 
                      buf, sizeof(buf), 12, "-2147483648", 0);
1021
 
 
1022
 
        CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, 0,
1023
 
                      buf, sizeof(buf), 14, "-549755813888", 0);
1024
 
 
1025
 
        CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, 0,
1026
 
                      buf, sizeof(buf), 17, "-140737488355328", 0);
1027
 
 
1028
 
        CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, 0,
1029
 
                      buf, sizeof(buf), 19, "-36028797018963968", 0);
1030
 
 
1031
 
        CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, 0,
1032
 
                      buf, sizeof(buf), 21, "-9223372036854775808", 0);
1033
 
 
1034
 
        /* min values for unsigned 1-8 byte integers */
1035
 
 
1036
 
        CALL_AND_TEST("\x00", 1, DATA_UNSIGNED,
1037
 
                      buf, sizeof(buf), 2, "0", 0);
1038
 
 
1039
 
        CALL_AND_TEST("\x00\x00", 2, DATA_UNSIGNED,
1040
 
                      buf, sizeof(buf), 2, "0", 0);
1041
 
 
1042
 
        CALL_AND_TEST("\x00\x00\x00", 3, DATA_UNSIGNED,
1043
 
                      buf, sizeof(buf), 2, "0", 0);
1044
 
 
1045
 
        CALL_AND_TEST("\x00\x00\x00\x00", 4, DATA_UNSIGNED,
1046
 
                      buf, sizeof(buf), 2, "0", 0);
1047
 
 
1048
 
        CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, DATA_UNSIGNED,
1049
 
                      buf, sizeof(buf), 2, "0", 0);
1050
 
 
1051
 
        CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, DATA_UNSIGNED,
1052
 
                      buf, sizeof(buf), 2, "0", 0);
1053
 
 
1054
 
        CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, DATA_UNSIGNED,
1055
 
                      buf, sizeof(buf), 2, "0", 0);
1056
 
 
1057
 
        CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, DATA_UNSIGNED,
1058
 
                      buf, sizeof(buf), 2, "0", 0);
1059
 
 
1060
 
        /* max values for signed 1-8 byte integers */
1061
 
 
1062
 
        CALL_AND_TEST("\xFF", 1, 0,
1063
 
                      buf, sizeof(buf), 4, "127", 0);
1064
 
 
1065
 
        CALL_AND_TEST("\xFF\xFF", 2, 0,
1066
 
                      buf, sizeof(buf), 6, "32767", 0);
1067
 
 
1068
 
        CALL_AND_TEST("\xFF\xFF\xFF", 3, 0,
1069
 
                      buf, sizeof(buf), 8, "8388607", 0);
1070
 
 
1071
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, 0,
1072
 
                      buf, sizeof(buf), 11, "2147483647", 0);
1073
 
 
1074
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, 0,
1075
 
                      buf, sizeof(buf), 13, "549755813887", 0);
1076
 
 
1077
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, 0,
1078
 
                      buf, sizeof(buf), 16, "140737488355327", 0);
1079
 
 
1080
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, 0,
1081
 
                      buf, sizeof(buf), 18, "36028797018963967", 0);
1082
 
 
1083
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, 0,
1084
 
                      buf, sizeof(buf), 20, "9223372036854775807", 0);
1085
 
 
1086
 
        /* max values for unsigned 1-8 byte integers */
1087
 
 
1088
 
        CALL_AND_TEST("\xFF", 1, DATA_UNSIGNED,
1089
 
                      buf, sizeof(buf), 4, "255", 0);
1090
 
 
1091
 
        CALL_AND_TEST("\xFF\xFF", 2, DATA_UNSIGNED,
1092
 
                      buf, sizeof(buf), 6, "65535", 0);
1093
 
 
1094
 
        CALL_AND_TEST("\xFF\xFF\xFF", 3, DATA_UNSIGNED,
1095
 
                      buf, sizeof(buf), 9, "16777215", 0);
1096
 
 
1097
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, DATA_UNSIGNED,
1098
 
                      buf, sizeof(buf), 11, "4294967295", 0);
1099
 
 
1100
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, DATA_UNSIGNED,
1101
 
                      buf, sizeof(buf), 14, "1099511627775", 0);
1102
 
 
1103
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, DATA_UNSIGNED,
1104
 
                      buf, sizeof(buf), 16, "281474976710655", 0);
1105
 
 
1106
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, DATA_UNSIGNED,
1107
 
                      buf, sizeof(buf), 18, "72057594037927935", 0);
1108
 
 
1109
 
        CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, DATA_UNSIGNED,
1110
 
                      buf, sizeof(buf), 21, "18446744073709551615", 0);
1111
 
 
1112
 
        /* some random values */
1113
 
 
1114
 
        CALL_AND_TEST("\x52", 1, 0,
1115
 
                      buf, sizeof(buf), 4, "-46", 0);
1116
 
 
1117
 
        CALL_AND_TEST("\x0E", 1, DATA_UNSIGNED,
1118
 
                      buf, sizeof(buf), 3, "14", 0);
1119
 
 
1120
 
        CALL_AND_TEST("\x62\xCE", 2, 0,
1121
 
                      buf, sizeof(buf), 6, "-7474", 0);
1122
 
 
1123
 
        CALL_AND_TEST("\x29\xD6", 2, DATA_UNSIGNED,
1124
 
                      buf, sizeof(buf), 6, "10710", 0);
1125
 
 
1126
 
        CALL_AND_TEST("\x7F\xFF\x90", 3, 0,
1127
 
                      buf, sizeof(buf), 5, "-112", 0);
1128
 
 
1129
 
        CALL_AND_TEST("\x00\xA1\x16", 3, DATA_UNSIGNED,
1130
 
                      buf, sizeof(buf), 6, "41238", 0);
1131
 
 
1132
 
        CALL_AND_TEST("\x7F\xFF\xFF\xF7", 4, 0,
1133
 
                      buf, sizeof(buf), 3, "-9", 0);
1134
 
 
1135
 
        CALL_AND_TEST("\x00\x00\x00\x5C", 4, DATA_UNSIGNED,
1136
 
                      buf, sizeof(buf), 3, "92", 0);
1137
 
 
1138
 
        CALL_AND_TEST("\x7F\xFF\xFF\xFF\xFF\xFF\xDC\x63", 8, 0,
1139
 
                      buf, sizeof(buf), 6, "-9117", 0);
1140
 
 
1141
 
        CALL_AND_TEST("\x00\x00\x00\x00\x00\x01\x64\x62", 8, DATA_UNSIGNED,
1142
 
                      buf, sizeof(buf), 6, "91234", 0);
1143
 
#endif
1144
 
 
1145
 
        /* speed test */
1146
 
 
1147
 
        speedo_t        speedo;
1148
 
        ulint           i;
1149
 
 
1150
 
        speedo_reset(&speedo);
1151
 
 
1152
 
        for (i = 0; i < 1000000; i++) {
1153
 
                row_raw_format_int("\x23", 1,
1154
 
                                   0, buf, sizeof(buf),
1155
 
                                   &format_in_hex);
1156
 
                row_raw_format_int("\x23", 1,
1157
 
                                   DATA_UNSIGNED, buf, sizeof(buf),
1158
 
                                   &format_in_hex);
1159
 
 
1160
 
                row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1161
 
                                   0, buf, sizeof(buf),
1162
 
                                   &format_in_hex);
1163
 
                row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1164
 
                                   DATA_UNSIGNED, buf, sizeof(buf),
1165
 
                                   &format_in_hex);
1166
 
        }
1167
 
 
1168
 
        speedo_show(&speedo);
1169
 
}
1170
 
 
1171
 
#endif /* UNIV_COMPILE_TEST_FUNCS */