2005-10-27 09:29:40 +02:00
|
|
|
/******************************************************
|
|
|
|
General row routines
|
|
|
|
|
|
|
|
(c) 1996 Innobase Oy
|
|
|
|
|
|
|
|
Created 4/20/1996 Heikki Tuuri
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
#include "row0row.h"
|
|
|
|
|
|
|
|
#ifdef UNIV_NONINL
|
|
|
|
#include "row0row.ic"
|
|
|
|
#endif
|
|
|
|
|
2007-10-29 14:03:53 +01:00
|
|
|
#include "data0type.h"
|
2005-10-27 09:29:40 +02:00
|
|
|
#include "dict0dict.h"
|
|
|
|
#include "btr0btr.h"
|
2007-10-29 14:03:53 +01:00
|
|
|
#include "ha_prototypes.h"
|
2005-10-27 09:29:40 +02:00
|
|
|
#include "mach0data.h"
|
|
|
|
#include "trx0rseg.h"
|
|
|
|
#include "trx0trx.h"
|
|
|
|
#include "trx0roll.h"
|
|
|
|
#include "trx0undo.h"
|
|
|
|
#include "trx0purge.h"
|
|
|
|
#include "trx0rec.h"
|
|
|
|
#include "que0que.h"
|
2006-09-26 13:50:54 +02:00
|
|
|
#include "row0ext.h"
|
2005-10-27 09:29:40 +02:00
|
|
|
#include "row0upd.h"
|
|
|
|
#include "rem0cmp.h"
|
|
|
|
#include "read0read.h"
|
2007-10-29 14:03:53 +01:00
|
|
|
#include "ut0mem.h"
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/*************************************************************************
|
2006-02-10 16:06:17 +01:00
|
|
|
Gets the offset of trx id field, in bytes relative to the origin of
|
|
|
|
a clustered index record. */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-10 16:06:17 +01:00
|
|
|
ulint
|
|
|
|
row_get_trx_id_offset(
|
2005-10-27 09:29:40 +02:00
|
|
|
/*==================*/
|
2006-02-10 16:06:17 +01:00
|
|
|
/* out: offset of DATA_TRX_ID */
|
2006-10-20 15:50:40 +02:00
|
|
|
const rec_t* rec __attribute__((unused)),
|
|
|
|
/* in: record */
|
2005-10-27 09:29:40 +02:00
|
|
|
dict_index_t* index, /* in: clustered index */
|
|
|
|
const ulint* offsets)/* in: rec_get_offsets(rec, index) */
|
|
|
|
{
|
|
|
|
ulint pos;
|
2006-10-20 15:50:40 +02:00
|
|
|
ulint offset;
|
2005-10-27 09:29:40 +02:00
|
|
|
ulint len;
|
|
|
|
|
2006-03-09 18:26:02 +01:00
|
|
|
ut_ad(dict_index_is_clust(index));
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(rec_offs_validate(rec, index, offsets));
|
|
|
|
|
2006-02-10 16:06:17 +01:00
|
|
|
pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-10-20 15:50:40 +02:00
|
|
|
offset = rec_get_nth_field_offs(offsets, pos, &len);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-10 16:06:17 +01:00
|
|
|
ut_ad(len == DATA_TRX_ID_LEN);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-10-20 15:50:40 +02:00
|
|
|
return(offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************
|
2007-04-04 13:05:33 +02:00
|
|
|
When an insert or purge to a table is performed, this function builds
|
|
|
|
the entry to be inserted into or purged from an index on the table. */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
dtuple_t*
|
|
|
|
row_build_index_entry(
|
|
|
|
/*==================*/
|
2007-04-04 13:05:33 +02:00
|
|
|
/* out: index entry which should be
|
2007-11-27 10:11:45 +01:00
|
|
|
inserted or purged, or NULL if the
|
|
|
|
externally stored columns in the
|
|
|
|
clustered index record are unavailable
|
|
|
|
and ext != NULL */
|
2007-04-04 13:05:33 +02:00
|
|
|
const dtuple_t* row, /* in: row which should be
|
|
|
|
inserted or purged */
|
2006-09-26 13:50:54 +02:00
|
|
|
row_ext_t* ext, /* in: externally stored column prefixes,
|
|
|
|
or NULL */
|
2006-02-23 20:25:29 +01:00
|
|
|
dict_index_t* index, /* in: index on the table */
|
2005-10-27 09:29:40 +02:00
|
|
|
mem_heap_t* heap) /* in: memory heap from which the memory for
|
|
|
|
the index entry is allocated */
|
|
|
|
{
|
|
|
|
dtuple_t* entry;
|
|
|
|
ulint entry_len;
|
|
|
|
ulint i;
|
|
|
|
|
|
|
|
ut_ad(row && index && heap);
|
|
|
|
ut_ad(dtuple_check_typed(row));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
entry_len = dict_index_get_n_fields(index);
|
|
|
|
entry = dtuple_create(heap, entry_len);
|
|
|
|
|
|
|
|
if (index->type & DICT_UNIVERSAL) {
|
|
|
|
dtuple_set_n_fields_cmp(entry, entry_len);
|
2006-09-26 16:26:19 +02:00
|
|
|
ut_a(!ext);
|
2005-10-27 09:29:40 +02:00
|
|
|
} else {
|
2006-09-19 12:14:07 +02:00
|
|
|
dtuple_set_n_fields_cmp(
|
|
|
|
entry, dict_index_get_n_unique_in_tree(index));
|
2006-09-26 16:26:19 +02:00
|
|
|
if (dict_index_is_clust(index)) {
|
|
|
|
/* Do not fetch externally stored columns to
|
|
|
|
the clustered index. Such columns are handled
|
|
|
|
at a higher level. */
|
|
|
|
ext = NULL;
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < entry_len; i++) {
|
2007-10-23 08:46:12 +02:00
|
|
|
const dict_field_t* ind_field
|
|
|
|
= dict_index_get_nth_field(index, i);
|
|
|
|
const dict_col_t* col
|
|
|
|
= ind_field->col;
|
|
|
|
ulint col_no
|
|
|
|
= dict_col_get_no(col);
|
|
|
|
dfield_t* dfield
|
|
|
|
= dtuple_get_nth_field(entry, i);
|
|
|
|
const dfield_t* dfield2
|
|
|
|
= dtuple_get_nth_field(row, col_no);
|
|
|
|
ulint len
|
2007-10-24 08:59:01 +02:00
|
|
|
= dfield_get_len(dfield2);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
dfield_copy(dfield, dfield2);
|
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
if (UNIV_LIKELY_NULL(ext) && !dfield_is_null(dfield)) {
|
2006-09-26 13:50:54 +02:00
|
|
|
/* See if the column is stored externally. */
|
2007-11-29 13:47:18 +01:00
|
|
|
const byte* buf = row_ext_lookup(ext, col_no,
|
|
|
|
&len);
|
2006-09-26 13:50:54 +02:00
|
|
|
if (UNIV_LIKELY_NULL(buf)) {
|
2007-11-27 10:11:45 +01:00
|
|
|
if (UNIV_UNLIKELY(buf == field_ref_zero)) {
|
|
|
|
return(NULL);
|
|
|
|
}
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
dfield_set_data(dfield, buf, len);
|
2006-09-26 13:50:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/* If a column prefix index, take only the prefix */
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
if (ind_field->prefix_len > 0 && !dfield_is_null(dfield)) {
|
2007-10-23 08:46:12 +02:00
|
|
|
len = dtype_get_at_most_n_mbchars(
|
2007-05-29 10:48:16 +02:00
|
|
|
col->prtype, col->mbminlen, col->mbmaxlen,
|
|
|
|
ind_field->prefix_len,
|
2007-10-23 08:46:12 +02:00
|
|
|
len, dfield_get_data(dfield));
|
|
|
|
dfield_set_len(dfield, len);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(dtuple_check_typed(entry));
|
|
|
|
|
|
|
|
return(entry);
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/***********************************************************************
|
2007-06-08 09:37:07 +02:00
|
|
|
An inverse function to row_build_index_entry. Builds a row from a
|
2005-10-27 09:29:40 +02:00
|
|
|
record in a clustered index. */
|
|
|
|
|
|
|
|
dtuple_t*
|
|
|
|
row_build(
|
|
|
|
/*======*/
|
2007-12-03 13:16:07 +01:00
|
|
|
/* out, own: row built;
|
|
|
|
see the NOTE below! */
|
|
|
|
ulint type, /* in: ROW_COPY_POINTERS or
|
|
|
|
ROW_COPY_DATA; the latter
|
|
|
|
copies also the data fields to
|
|
|
|
heap while the first only
|
|
|
|
places pointers to data fields
|
|
|
|
on the index page, and thus is
|
|
|
|
more efficient */
|
|
|
|
const dict_index_t* index, /* in: clustered index */
|
|
|
|
const rec_t* rec, /* in: record in the clustered
|
|
|
|
index; NOTE: in the case
|
|
|
|
ROW_COPY_POINTERS the data
|
|
|
|
fields in the row will point
|
|
|
|
directly into this record,
|
|
|
|
therefore, the buffer page of
|
|
|
|
this record must be at least
|
|
|
|
s-latched and the latch held
|
|
|
|
as long as the row dtuple is used! */
|
|
|
|
const ulint* offsets,/* in: rec_get_offsets(rec,index)
|
|
|
|
or NULL, in which case this function
|
|
|
|
will invoke rec_get_offsets() */
|
|
|
|
const dict_table_t* col_table,
|
|
|
|
/* in: table, to check which
|
|
|
|
externally stored columns
|
|
|
|
occur in the ordering columns
|
|
|
|
of an index, or NULL if
|
|
|
|
index->table should be
|
|
|
|
consulted instead */
|
|
|
|
row_ext_t** ext, /* out, own: cache of
|
|
|
|
externally stored column
|
|
|
|
prefixes, or NULL */
|
|
|
|
mem_heap_t* heap) /* in: memory heap from which
|
|
|
|
the memory needed is allocated */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2007-12-03 13:16:07 +01:00
|
|
|
dtuple_t* row;
|
|
|
|
const dict_table_t* table;
|
|
|
|
ulint n_fields;
|
|
|
|
ulint n_ext_cols;
|
|
|
|
ulint* ext_cols = NULL; /* remove warning */
|
|
|
|
ulint len;
|
|
|
|
ulint row_len;
|
|
|
|
byte* buf;
|
|
|
|
ulint i;
|
|
|
|
ulint j;
|
|
|
|
mem_heap_t* tmp_heap = NULL;
|
|
|
|
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
2007-09-28 09:05:57 +02:00
|
|
|
rec_offs_init(offsets_);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
ut_ad(index && rec && heap);
|
2006-03-09 18:26:02 +01:00
|
|
|
ut_ad(dict_index_is_clust(index));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (!offsets) {
|
|
|
|
offsets = rec_get_offsets(rec, index, offsets_,
|
2006-08-29 11:30:31 +02:00
|
|
|
ULINT_UNDEFINED, &tmp_heap);
|
2005-10-27 09:29:40 +02:00
|
|
|
} else {
|
|
|
|
ut_ad(rec_offs_validate(rec, index, offsets));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != ROW_COPY_POINTERS) {
|
|
|
|
/* Take a copy of rec to heap */
|
|
|
|
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
|
|
|
|
rec = rec_copy(buf, rec, offsets);
|
|
|
|
/* Avoid a debug assertion in rec_offs_validate(). */
|
|
|
|
rec_offs_make_valid(rec, index, (ulint*) offsets);
|
|
|
|
}
|
|
|
|
|
|
|
|
table = index->table;
|
|
|
|
row_len = dict_table_get_n_cols(table);
|
|
|
|
|
|
|
|
row = dtuple_create(heap, row_len);
|
|
|
|
|
2006-09-19 12:14:07 +02:00
|
|
|
dtuple_set_info_bits(row, rec_get_info_bits(
|
|
|
|
rec, dict_table_is_comp(table)));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
n_fields = rec_offs_n_fields(offsets);
|
2006-09-26 13:50:54 +02:00
|
|
|
n_ext_cols = rec_offs_n_extern(offsets);
|
|
|
|
if (n_ext_cols) {
|
|
|
|
ext_cols = mem_heap_alloc(heap, n_ext_cols * sizeof *ext_cols);
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
dict_table_copy_types(row, table);
|
|
|
|
|
2006-09-26 13:50:54 +02:00
|
|
|
for (i = j = 0; i < n_fields; i++) {
|
|
|
|
dict_field_t* ind_field
|
|
|
|
= dict_index_get_nth_field(index, i);
|
|
|
|
const dict_col_t* col
|
|
|
|
= dict_field_get_col(ind_field);
|
2007-11-29 13:47:18 +01:00
|
|
|
ulint col_no
|
|
|
|
= dict_col_get_no(col);
|
2007-10-17 14:13:29 +02:00
|
|
|
dfield_t* dfield
|
2007-11-29 13:47:18 +01:00
|
|
|
= dtuple_get_nth_field(row, col_no);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (ind_field->prefix_len == 0) {
|
|
|
|
|
2006-10-20 15:50:40 +02:00
|
|
|
const byte* field = rec_get_nth_field(
|
2006-10-19 09:27:26 +02:00
|
|
|
rec, offsets, i, &len);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
dfield_set_data(dfield, field, len);
|
|
|
|
}
|
2006-09-26 13:50:54 +02:00
|
|
|
|
|
|
|
if (rec_offs_nth_extern(offsets, i)) {
|
2007-10-17 14:13:29 +02:00
|
|
|
dfield_set_ext(dfield);
|
2007-12-03 13:16:07 +01:00
|
|
|
|
|
|
|
if (UNIV_LIKELY_NULL(col_table)) {
|
|
|
|
ut_a(col_no
|
|
|
|
< dict_table_get_n_cols(col_table));
|
|
|
|
col = dict_table_get_nth_col(
|
|
|
|
col_table, col_no);
|
|
|
|
}
|
|
|
|
|
2007-11-29 13:47:18 +01:00
|
|
|
if (col->ord_part) {
|
|
|
|
/* We will have to fetch prefixes of
|
|
|
|
externally stored columns that are
|
|
|
|
referenced by column prefixes. */
|
|
|
|
ext_cols[j++] = col_no;
|
|
|
|
}
|
2006-09-26 13:50:54 +02:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(dtuple_check_typed(row));
|
|
|
|
|
2007-11-29 13:47:18 +01:00
|
|
|
if (j) {
|
|
|
|
*ext = row_ext_create(j, ext_cols, row,
|
2006-09-26 13:50:54 +02:00
|
|
|
dict_table_zip_size(index->table),
|
|
|
|
heap);
|
|
|
|
} else {
|
|
|
|
*ext = NULL;
|
|
|
|
}
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
if (tmp_heap) {
|
|
|
|
mem_heap_free(tmp_heap);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(row);
|
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/***********************************************************************
|
|
|
|
Converts an index record to a typed data tuple. */
|
|
|
|
|
|
|
|
dtuple_t*
|
|
|
|
row_rec_to_index_entry_low(
|
|
|
|
/*=======================*/
|
2007-10-17 14:13:29 +02:00
|
|
|
/* out: index entry built; does not
|
|
|
|
set info_bits, and the data fields in
|
|
|
|
the entry will point directly to rec */
|
|
|
|
const rec_t* rec, /* in: record in the index */
|
|
|
|
const dict_index_t* index, /* in: index */
|
|
|
|
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
|
|
|
|
ulint* n_ext, /* out: number of externally
|
|
|
|
stored columns */
|
|
|
|
mem_heap_t* heap) /* in: memory heap from which
|
|
|
|
the memory needed is allocated */
|
2007-06-08 09:37:07 +02:00
|
|
|
{
|
|
|
|
dtuple_t* entry;
|
|
|
|
dfield_t* dfield;
|
|
|
|
ulint i;
|
|
|
|
const byte* field;
|
|
|
|
ulint len;
|
|
|
|
ulint rec_len;
|
|
|
|
|
|
|
|
ut_ad(rec && heap && index);
|
2007-10-22 12:23:13 +02:00
|
|
|
/* Because this function may be invoked by row0merge.c
|
|
|
|
on a record whose header is in different format, the check
|
|
|
|
rec_offs_validate(rec, index, offsets) must be avoided here. */
|
2007-10-17 14:13:29 +02:00
|
|
|
ut_ad(n_ext);
|
|
|
|
*n_ext = 0;
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
rec_len = rec_offs_n_fields(offsets);
|
|
|
|
|
|
|
|
entry = dtuple_create(heap, rec_len);
|
|
|
|
|
|
|
|
dtuple_set_n_fields_cmp(entry,
|
|
|
|
dict_index_get_n_unique_in_tree(index));
|
|
|
|
ut_ad(rec_len == dict_index_get_n_fields(index));
|
|
|
|
|
|
|
|
dict_index_copy_types(entry, index, rec_len);
|
|
|
|
|
|
|
|
for (i = 0; i < rec_len; i++) {
|
|
|
|
|
|
|
|
dfield = dtuple_get_nth_field(entry, i);
|
|
|
|
field = rec_get_nth_field(rec, offsets, i, &len);
|
|
|
|
|
|
|
|
dfield_set_data(dfield, field, len);
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
|
2007-10-17 14:13:29 +02:00
|
|
|
if (rec_offs_nth_extern(offsets, i)) {
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
dfield_set_ext(dfield);
|
|
|
|
(*n_ext)++;
|
|
|
|
}
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(dtuple_check_typed(entry));
|
|
|
|
|
|
|
|
return(entry);
|
|
|
|
}
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/***********************************************************************
|
|
|
|
Converts an index record to a typed data tuple. NOTE that externally
|
|
|
|
stored (often big) fields are NOT copied to heap. */
|
|
|
|
|
|
|
|
dtuple_t*
|
|
|
|
row_rec_to_index_entry(
|
|
|
|
/*===================*/
|
2007-10-17 14:13:29 +02:00
|
|
|
/* out, own: index entry
|
|
|
|
built; see the NOTE below! */
|
|
|
|
ulint type, /* in: ROW_COPY_DATA, or
|
|
|
|
ROW_COPY_POINTERS: the former
|
|
|
|
copies also the data fields to
|
|
|
|
heap as the latter only places
|
|
|
|
pointers to data fields on the
|
|
|
|
index page */
|
|
|
|
const rec_t* rec, /* in: record in the index;
|
|
|
|
NOTE: in the case
|
|
|
|
ROW_COPY_POINTERS the data
|
|
|
|
fields in the row will point
|
|
|
|
directly into this record,
|
|
|
|
therefore, the buffer page of
|
|
|
|
this record must be at least
|
|
|
|
s-latched and the latch held
|
|
|
|
as long as the dtuple is used! */
|
|
|
|
const dict_index_t* index, /* in: index */
|
|
|
|
ulint* offsets,/* in/out: rec_get_offsets(rec) */
|
|
|
|
ulint* n_ext, /* out: number of externally
|
|
|
|
stored columns */
|
|
|
|
mem_heap_t* heap) /* in: memory heap from which
|
|
|
|
the memory needed is allocated */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
|
|
|
dtuple_t* entry;
|
|
|
|
byte* buf;
|
|
|
|
|
|
|
|
ut_ad(rec && heap && index);
|
2007-10-17 14:13:29 +02:00
|
|
|
ut_ad(rec_offs_validate(rec, index, offsets));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (type == ROW_COPY_DATA) {
|
|
|
|
/* Take a copy of rec to heap */
|
|
|
|
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
|
|
|
|
rec = rec_copy(buf, rec, offsets);
|
|
|
|
/* Avoid a debug assertion in rec_offs_validate(). */
|
|
|
|
rec_offs_make_valid(rec, index, offsets);
|
|
|
|
}
|
|
|
|
|
2007-10-17 14:13:29 +02:00
|
|
|
entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
dtuple_set_info_bits(entry,
|
2006-08-29 11:30:31 +02:00
|
|
|
rec_get_info_bits(rec, rec_offs_comp(offsets)));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
return(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Builds from a secondary index record a row reference with which we can
|
|
|
|
search the clustered index record. */
|
|
|
|
|
|
|
|
dtuple_t*
|
|
|
|
row_build_row_ref(
|
|
|
|
/*==============*/
|
|
|
|
/* out, own: row reference built; see the
|
|
|
|
NOTE below! */
|
|
|
|
ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
|
|
|
|
the former copies also the data fields to
|
|
|
|
heap, whereas the latter only places pointers
|
|
|
|
to data fields on the index page */
|
2007-10-17 14:13:29 +02:00
|
|
|
dict_index_t* index, /* in: secondary index */
|
2006-10-20 15:50:40 +02:00
|
|
|
const rec_t* rec, /* in: record in the index;
|
2005-10-27 09:29:40 +02:00
|
|
|
NOTE: in the case ROW_COPY_POINTERS
|
|
|
|
the data fields in the row will point
|
|
|
|
directly into this record, therefore,
|
|
|
|
the buffer page of this record must be
|
|
|
|
at least s-latched and the latch held
|
|
|
|
as long as the row reference is used! */
|
|
|
|
mem_heap_t* heap) /* in: memory heap from which the memory
|
|
|
|
needed is allocated */
|
|
|
|
{
|
|
|
|
dict_table_t* table;
|
|
|
|
dict_index_t* clust_index;
|
|
|
|
dfield_t* dfield;
|
|
|
|
dtuple_t* ref;
|
2006-10-20 15:50:40 +02:00
|
|
|
const byte* field;
|
2005-10-27 09:29:40 +02:00
|
|
|
ulint len;
|
|
|
|
ulint ref_len;
|
|
|
|
ulint pos;
|
|
|
|
byte* buf;
|
|
|
|
ulint clust_col_prefix_len;
|
|
|
|
ulint i;
|
|
|
|
mem_heap_t* tmp_heap = NULL;
|
|
|
|
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
|
|
|
ulint* offsets = offsets_;
|
2007-09-28 09:05:57 +02:00
|
|
|
rec_offs_init(offsets_);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
ut_ad(index && rec && heap);
|
2007-10-17 14:13:29 +02:00
|
|
|
ut_ad(!dict_index_is_clust(index));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
offsets = rec_get_offsets(rec, index, offsets,
|
2006-08-29 11:30:31 +02:00
|
|
|
ULINT_UNDEFINED, &tmp_heap);
|
2007-10-17 14:13:29 +02:00
|
|
|
/* Secondary indexes must not contain externally stored columns. */
|
|
|
|
ut_ad(!rec_offs_any_extern(offsets));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (type == ROW_COPY_DATA) {
|
|
|
|
/* Take a copy of rec to heap */
|
|
|
|
|
|
|
|
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
|
|
|
|
|
|
|
|
rec = rec_copy(buf, rec, offsets);
|
|
|
|
/* Avoid a debug assertion in rec_offs_validate(). */
|
|
|
|
rec_offs_make_valid(rec, index, offsets);
|
|
|
|
}
|
|
|
|
|
|
|
|
table = index->table;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
clust_index = dict_table_get_first_index(table);
|
|
|
|
|
|
|
|
ref_len = dict_index_get_n_unique(clust_index);
|
|
|
|
|
|
|
|
ref = dtuple_create(heap, ref_len);
|
|
|
|
|
|
|
|
dict_index_copy_types(ref, clust_index, ref_len);
|
|
|
|
|
|
|
|
for (i = 0; i < ref_len; i++) {
|
2006-10-19 09:27:26 +02:00
|
|
|
dfield = dtuple_get_nth_field(ref, i);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
pos = dict_index_get_nth_field_pos(index, clust_index, i);
|
|
|
|
|
|
|
|
ut_a(pos != ULINT_UNDEFINED);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
field = rec_get_nth_field(rec, offsets, pos, &len);
|
|
|
|
|
|
|
|
dfield_set_data(dfield, field, len);
|
|
|
|
|
|
|
|
/* If the primary key contains a column prefix, then the
|
|
|
|
secondary index may contain a longer prefix of the same
|
|
|
|
column, or the full column, and we must adjust the length
|
|
|
|
accordingly. */
|
|
|
|
|
2006-09-19 12:14:07 +02:00
|
|
|
clust_col_prefix_len = dict_index_get_nth_field(
|
|
|
|
clust_index, i)->prefix_len;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (clust_col_prefix_len > 0) {
|
2006-02-23 20:25:29 +01:00
|
|
|
if (len != UNIV_SQL_NULL) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-09-19 12:14:07 +02:00
|
|
|
const dtype_t* dtype
|
|
|
|
= dfield_get_type(dfield);
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
dfield_set_len(dfield,
|
2006-09-19 12:14:07 +02:00
|
|
|
dtype_get_at_most_n_mbchars(
|
|
|
|
dtype->prtype,
|
|
|
|
dtype->mbminlen,
|
|
|
|
dtype->mbmaxlen,
|
|
|
|
clust_col_prefix_len,
|
|
|
|
len, (char*) field));
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(dtuple_check_typed(ref));
|
|
|
|
if (tmp_heap) {
|
|
|
|
mem_heap_free(tmp_heap);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Builds from a secondary index record a row reference with which we can
|
|
|
|
search the clustered index record. */
|
|
|
|
|
|
|
|
void
|
|
|
|
row_build_row_ref_in_tuple(
|
|
|
|
/*=======================*/
|
2007-09-25 09:20:56 +02:00
|
|
|
dtuple_t* ref, /* in/out: row reference built;
|
|
|
|
see the NOTE below! */
|
|
|
|
const rec_t* rec, /* in: record in the index;
|
|
|
|
NOTE: the data fields in ref
|
|
|
|
will point directly into this
|
|
|
|
record, therefore, the buffer
|
|
|
|
page of this record must be at
|
|
|
|
least s-latched and the latch
|
|
|
|
held as long as the row
|
|
|
|
reference is used! */
|
|
|
|
const dict_index_t* index, /* in: secondary index */
|
|
|
|
ulint* offsets,/* in: rec_get_offsets(rec, index)
|
|
|
|
or NULL */
|
|
|
|
trx_t* trx) /* in: transaction */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2007-09-25 09:20:56 +02:00
|
|
|
const dict_index_t* clust_index;
|
|
|
|
dfield_t* dfield;
|
|
|
|
const byte* field;
|
|
|
|
ulint len;
|
|
|
|
ulint ref_len;
|
|
|
|
ulint pos;
|
|
|
|
ulint clust_col_prefix_len;
|
|
|
|
ulint i;
|
|
|
|
mem_heap_t* heap = NULL;
|
|
|
|
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
2007-09-28 09:05:57 +02:00
|
|
|
rec_offs_init(offsets_);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-05-29 10:48:16 +02:00
|
|
|
ut_a(ref);
|
|
|
|
ut_a(index);
|
|
|
|
ut_a(rec);
|
2007-09-25 09:20:56 +02:00
|
|
|
ut_ad(!dict_index_is_clust(index));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-06-13 22:23:26 +02:00
|
|
|
if (UNIV_UNLIKELY(!index->table)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
fputs("InnoDB: table ", stderr);
|
2006-08-29 11:30:31 +02:00
|
|
|
notfound:
|
2006-06-13 22:23:26 +02:00
|
|
|
ut_print_name(stderr, trx, TRUE, index->table_name);
|
2005-10-27 09:29:40 +02:00
|
|
|
fputs(" for index ", stderr);
|
2006-06-13 22:23:26 +02:00
|
|
|
ut_print_name(stderr, trx, FALSE, index->name);
|
2005-10-27 09:29:40 +02:00
|
|
|
fputs(" not found\n", stderr);
|
|
|
|
ut_error;
|
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
clust_index = dict_table_get_first_index(index->table);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2007-09-25 09:20:56 +02:00
|
|
|
if (UNIV_UNLIKELY(!clust_index)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
fputs("InnoDB: clust index for table ", stderr);
|
|
|
|
goto notfound;
|
|
|
|
}
|
|
|
|
|
2007-09-25 09:20:56 +02:00
|
|
|
if (!offsets) {
|
|
|
|
offsets = rec_get_offsets(rec, index, offsets_,
|
|
|
|
ULINT_UNDEFINED, &heap);
|
|
|
|
} else {
|
|
|
|
ut_ad(rec_offs_validate(rec, index, offsets));
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-10-17 14:13:29 +02:00
|
|
|
/* Secondary indexes must not contain externally stored columns. */
|
|
|
|
ut_ad(!rec_offs_any_extern(offsets));
|
2005-10-27 09:29:40 +02:00
|
|
|
ref_len = dict_index_get_n_unique(clust_index);
|
|
|
|
|
|
|
|
ut_ad(ref_len == dtuple_get_n_fields(ref));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
dict_index_copy_types(ref, clust_index, ref_len);
|
|
|
|
|
|
|
|
for (i = 0; i < ref_len; i++) {
|
2006-10-19 09:27:26 +02:00
|
|
|
dfield = dtuple_get_nth_field(ref, i);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
pos = dict_index_get_nth_field_pos(index, clust_index, i);
|
|
|
|
|
|
|
|
ut_a(pos != ULINT_UNDEFINED);
|
|
|
|
|
|
|
|
field = rec_get_nth_field(rec, offsets, pos, &len);
|
|
|
|
|
|
|
|
dfield_set_data(dfield, field, len);
|
|
|
|
|
|
|
|
/* If the primary key contains a column prefix, then the
|
|
|
|
secondary index may contain a longer prefix of the same
|
|
|
|
column, or the full column, and we must adjust the length
|
|
|
|
accordingly. */
|
|
|
|
|
2006-09-19 12:14:07 +02:00
|
|
|
clust_col_prefix_len = dict_index_get_nth_field(
|
|
|
|
clust_index, i)->prefix_len;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (clust_col_prefix_len > 0) {
|
2006-02-23 20:25:29 +01:00
|
|
|
if (len != UNIV_SQL_NULL) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-09-19 12:14:07 +02:00
|
|
|
const dtype_t* dtype
|
|
|
|
= dfield_get_type(dfield);
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
dfield_set_len(dfield,
|
2006-09-19 12:14:07 +02:00
|
|
|
dtype_get_at_most_n_mbchars(
|
|
|
|
dtype->prtype,
|
|
|
|
dtype->mbminlen,
|
|
|
|
dtype->mbmaxlen,
|
|
|
|
clust_col_prefix_len,
|
|
|
|
len, (char*) field));
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(dtuple_check_typed(ref));
|
|
|
|
if (UNIV_LIKELY_NULL(heap)) {
|
|
|
|
mem_heap_free(heap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
From a row build a row reference with which we can search the clustered
|
|
|
|
index record. */
|
|
|
|
|
|
|
|
void
|
|
|
|
row_build_row_ref_from_row(
|
|
|
|
/*=======================*/
|
2007-09-26 09:45:08 +02:00
|
|
|
dtuple_t* ref, /* in/out: row reference built;
|
|
|
|
see the NOTE below!
|
|
|
|
ref must have the right number
|
|
|
|
of fields! */
|
|
|
|
const dict_table_t* table, /* in: table */
|
|
|
|
const dtuple_t* row) /* in: row
|
|
|
|
NOTE: the data fields in ref will point
|
|
|
|
directly into data of this row */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2007-09-26 09:45:08 +02:00
|
|
|
const dict_index_t* clust_index;
|
|
|
|
ulint ref_len;
|
|
|
|
ulint i;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(ref && table && row);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
clust_index = dict_table_get_first_index(table);
|
|
|
|
|
|
|
|
ref_len = dict_index_get_n_unique(clust_index);
|
|
|
|
|
|
|
|
ut_ad(ref_len == dtuple_get_n_fields(ref));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
for (i = 0; i < ref_len; i++) {
|
2006-09-19 12:14:07 +02:00
|
|
|
const dict_col_t* col;
|
2007-09-26 09:45:08 +02:00
|
|
|
const dict_field_t* field;
|
2006-09-19 12:14:07 +02:00
|
|
|
dfield_t* dfield;
|
2006-10-17 14:24:13 +02:00
|
|
|
const dfield_t* dfield2;
|
2006-09-19 12:14:07 +02:00
|
|
|
|
2006-10-19 09:27:26 +02:00
|
|
|
dfield = dtuple_get_nth_field(ref, i);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
field = dict_index_get_nth_field(clust_index, i);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
col = dict_field_get_col(field);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col));
|
|
|
|
|
|
|
|
dfield_copy(dfield, dfield2);
|
2007-10-17 14:13:29 +02:00
|
|
|
ut_ad(!dfield_is_ext(dfield));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
if (field->prefix_len > 0 && !dfield_is_null(dfield)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-10-23 08:46:12 +02:00
|
|
|
ulint len = dfield_get_len(dfield);
|
|
|
|
|
|
|
|
len = dtype_get_at_most_n_mbchars(
|
2006-09-19 12:14:07 +02:00
|
|
|
col->prtype, col->mbminlen, col->mbmaxlen,
|
2007-10-23 08:46:12 +02:00
|
|
|
field->prefix_len,
|
|
|
|
len, dfield_get_data(dfield));
|
|
|
|
|
|
|
|
dfield_set_len(dfield, len);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(dtuple_check_typed(ref));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
Searches the clustered index record for a row, if we have the row reference. */
|
|
|
|
|
|
|
|
ibool
|
|
|
|
row_search_on_row_ref(
|
|
|
|
/*==================*/
|
2007-09-26 11:12:23 +02:00
|
|
|
/* out: TRUE if found */
|
|
|
|
btr_pcur_t* pcur, /* out: persistent cursor, which must
|
|
|
|
be closed by the caller */
|
|
|
|
ulint mode, /* in: BTR_MODIFY_LEAF, ... */
|
|
|
|
const dict_table_t* table, /* in: table */
|
|
|
|
const dtuple_t* ref, /* in: row reference */
|
|
|
|
mtr_t* mtr) /* in/out: mtr */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2006-02-23 20:25:29 +01:00
|
|
|
ulint low_match;
|
2005-10-27 09:29:40 +02:00
|
|
|
rec_t* rec;
|
|
|
|
dict_index_t* index;
|
|
|
|
|
|
|
|
ut_ad(dtuple_check_typed(ref));
|
|
|
|
|
|
|
|
index = dict_table_get_first_index(table);
|
|
|
|
|
|
|
|
ut_a(dtuple_get_n_fields(ref) == dict_index_get_n_unique(index));
|
|
|
|
|
|
|
|
btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
low_match = btr_pcur_get_low_match(pcur);
|
|
|
|
|
|
|
|
rec = btr_pcur_get_rec(pcur);
|
|
|
|
|
|
|
|
if (page_rec_is_infimum(rec)) {
|
|
|
|
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (low_match != dtuple_get_n_fields(ref)) {
|
|
|
|
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Fetches the clustered index record for a secondary index record. The latches
|
|
|
|
on the secondary index record are preserved. */
|
|
|
|
|
|
|
|
rec_t*
|
|
|
|
row_get_clust_rec(
|
|
|
|
/*==============*/
|
|
|
|
/* out: record or NULL, if no record found */
|
|
|
|
ulint mode, /* in: BTR_MODIFY_LEAF, ... */
|
2006-10-20 15:50:40 +02:00
|
|
|
const rec_t* rec, /* in: record in a secondary index */
|
2005-10-27 09:29:40 +02:00
|
|
|
dict_index_t* index, /* in: secondary index */
|
|
|
|
dict_index_t** clust_index,/* out: clustered index */
|
|
|
|
mtr_t* mtr) /* in: mtr */
|
|
|
|
{
|
|
|
|
mem_heap_t* heap;
|
|
|
|
dtuple_t* ref;
|
|
|
|
dict_table_t* table;
|
|
|
|
btr_pcur_t pcur;
|
|
|
|
ibool found;
|
|
|
|
rec_t* clust_rec;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-03-09 18:26:02 +01:00
|
|
|
ut_ad(!dict_index_is_clust(index));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
table = index->table;
|
|
|
|
|
|
|
|
heap = mem_heap_create(256);
|
|
|
|
|
|
|
|
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
|
|
|
|
|
|
|
|
found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
|
|
|
|
|
|
|
|
clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
|
|
|
|
|
|
|
|
mem_heap_free(heap);
|
|
|
|
|
|
|
|
btr_pcur_close(&pcur);
|
|
|
|
|
|
|
|
*clust_index = dict_table_get_first_index(table);
|
|
|
|
|
|
|
|
return(clust_rec);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
Searches an index record. */
|
|
|
|
|
|
|
|
ibool
|
|
|
|
row_search_index_entry(
|
|
|
|
/*===================*/
|
|
|
|
/* out: TRUE if found */
|
|
|
|
dict_index_t* index, /* in: index */
|
2006-10-20 15:50:40 +02:00
|
|
|
const dtuple_t* entry, /* in: index entry */
|
2005-10-27 09:29:40 +02:00
|
|
|
ulint mode, /* in: BTR_MODIFY_LEAF, ... */
|
|
|
|
btr_pcur_t* pcur, /* in/out: persistent cursor, which must
|
|
|
|
be closed by the caller */
|
|
|
|
mtr_t* mtr) /* in: mtr */
|
|
|
|
{
|
|
|
|
ulint n_fields;
|
|
|
|
ulint low_match;
|
|
|
|
rec_t* rec;
|
|
|
|
|
|
|
|
ut_ad(dtuple_check_typed(entry));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
|
|
|
|
low_match = btr_pcur_get_low_match(pcur);
|
|
|
|
|
|
|
|
rec = btr_pcur_get_rec(pcur);
|
|
|
|
|
|
|
|
n_fields = dtuple_get_n_fields(entry);
|
|
|
|
|
2006-09-25 14:17:33 +02:00
|
|
|
return(!page_rec_is_infimum(rec) && low_match == n_fields);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
2007-10-29 14:03:53 +01:00
|
|
|
|
|
|
|
#ifndef UNIV_HOTBACKUP
|
|
|
|
|
|
|
|
#include <my_sys.h>
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Formats the raw data in "data" (in InnoDB on-disk format) that is of
|
|
|
|
type DATA_INT using "prtype" and writes the result to "buf".
|
|
|
|
If the data is in unknown format, then nothing is written to "buf",
|
|
|
|
0 is returned and "format_in_hex" is set to TRUE, otherwise
|
|
|
|
"format_in_hex" is left untouched.
|
|
|
|
Not more than "buf_size" bytes are written to "buf".
|
|
|
|
The result is always '\0'-terminated (provided buf_size > 0) and the
|
|
|
|
number of bytes that were written to "buf" is returned (including the
|
|
|
|
terminating '\0'). */
|
|
|
|
static
|
|
|
|
ulint
|
|
|
|
row_raw_format_int(
|
|
|
|
/*===============*/
|
|
|
|
/* out: number of bytes
|
|
|
|
that were written */
|
|
|
|
const char* data, /* in: raw data */
|
|
|
|
ulint data_len, /* in: raw data length
|
|
|
|
in bytes */
|
|
|
|
ulint prtype, /* in: precise type */
|
|
|
|
char* buf, /* out: output buffer */
|
|
|
|
ulint buf_size, /* in: output buffer size
|
|
|
|
in bytes */
|
|
|
|
ibool* format_in_hex) /* out: should the data be
|
|
|
|
formated in hex */
|
|
|
|
{
|
|
|
|
ulint ret;
|
|
|
|
|
|
|
|
if (data_len <= sizeof(ullint)) {
|
|
|
|
|
|
|
|
ullint value;
|
|
|
|
ibool unsigned_type = prtype & DATA_UNSIGNED;
|
|
|
|
|
|
|
|
value = mach_read_int_type((const byte*) data,
|
|
|
|
data_len, unsigned_type);
|
|
|
|
|
|
|
|
if (unsigned_type) {
|
|
|
|
|
|
|
|
ret = ut_snprintf(buf, buf_size, "%llu",
|
|
|
|
value) + 1;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
ret = ut_snprintf(buf, buf_size, "%lld",
|
|
|
|
(long long) value) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
*format_in_hex = TRUE;
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return(ut_min(ret, buf_size));
|
|
|
|
}
|
|
|
|
|
|
|
|
extern CHARSET_INFO* system_charset_info;
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Formats the raw data in "data" (in InnoDB on-disk format) that is of
|
|
|
|
type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "charset_coll" and writes
|
|
|
|
the result to "buf". The result is converted to "system_charset_info".
|
|
|
|
Not more than "buf_size" bytes are written to "buf".
|
|
|
|
The result is always '\0'-terminated (provided buf_size > 0) and the
|
|
|
|
number of bytes that were written to "buf" is returned (including the
|
|
|
|
terminating '\0'). */
|
|
|
|
static
|
|
|
|
ulint
|
|
|
|
row_raw_format_str_convert(
|
|
|
|
/*=======================*/
|
|
|
|
/* out: number of bytes
|
|
|
|
that were written */
|
|
|
|
const char* data, /* in: raw data */
|
|
|
|
ulint data_len, /* in: raw data length
|
|
|
|
in bytes */
|
|
|
|
ulint charset_coll, /* in: charset collation */
|
|
|
|
char* buf, /* out: output buffer */
|
|
|
|
ulint buf_size) /* in: output buffer size
|
|
|
|
in bytes */
|
|
|
|
{
|
|
|
|
/* XXX we use a hard limit instead of allocating
|
|
|
|
but_size bytes from the heap */
|
|
|
|
CHARSET_INFO* data_cs;
|
|
|
|
char buf_tmp[8192];
|
|
|
|
ulint buf_tmp_used;
|
|
|
|
uint num_errors;
|
|
|
|
|
|
|
|
data_cs = all_charsets[charset_coll];
|
|
|
|
|
|
|
|
buf_tmp_used = innobase_convert_string(buf_tmp, sizeof(buf_tmp),
|
|
|
|
system_charset_info,
|
|
|
|
data, data_len, data_cs,
|
|
|
|
&num_errors);
|
|
|
|
|
|
|
|
return(ut_str_sql_format(buf_tmp, buf_tmp_used, buf, buf_size));
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Formats the raw data in "data" (in InnoDB on-disk format) that is of
|
|
|
|
type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "prtype" and writes the
|
|
|
|
result to "buf".
|
|
|
|
If the data is in binary format, then nothing is written to "buf",
|
|
|
|
0 is returned and "format_in_hex" is set to TRUE, otherwise
|
|
|
|
"format_in_hex" is left untouched.
|
|
|
|
Not more than "buf_size" bytes are written to "buf".
|
|
|
|
The result is always '\0'-terminated (provided buf_size > 0) and the
|
|
|
|
number of bytes that were written to "buf" is returned (including the
|
|
|
|
terminating '\0'). */
|
|
|
|
static
|
|
|
|
ulint
|
|
|
|
row_raw_format_str(
|
|
|
|
/*===============*/
|
|
|
|
/* out: number of bytes
|
|
|
|
that were written */
|
|
|
|
const char* data, /* in: raw data */
|
|
|
|
ulint data_len, /* in: raw data length
|
|
|
|
in bytes */
|
|
|
|
ulint prtype, /* in: precise type */
|
|
|
|
char* buf, /* out: output buffer */
|
|
|
|
ulint buf_size, /* in: output buffer size
|
|
|
|
in bytes */
|
|
|
|
ibool* format_in_hex) /* out: should the data be
|
|
|
|
formated in hex */
|
|
|
|
{
|
|
|
|
ulint charset_coll;
|
|
|
|
|
|
|
|
if (buf_size == 0) {
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we assume system_charset_info is UTF-8 */
|
|
|
|
|
|
|
|
charset_coll = dtype_get_charset_coll(prtype);
|
|
|
|
|
|
|
|
if (UNIV_LIKELY(dtype_is_utf8(prtype))) {
|
|
|
|
|
|
|
|
return(ut_str_sql_format(data, data_len, buf, buf_size));
|
|
|
|
}
|
|
|
|
/* else */
|
|
|
|
|
|
|
|
if (charset_coll == DATA_MYSQL_BINARY_CHARSET_COLL) {
|
|
|
|
|
|
|
|
*format_in_hex = TRUE;
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
/* else */
|
|
|
|
|
|
|
|
return(row_raw_format_str_convert(data, data_len, charset_coll,
|
|
|
|
buf, buf_size));
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Formats the raw data in "data" (in InnoDB on-disk format) using
|
|
|
|
"dict_field" and writes the result to "buf".
|
|
|
|
Not more than "buf_size" bytes are written to "buf".
|
|
|
|
The result is always '\0'-terminated (provided buf_size > 0) and the
|
|
|
|
number of bytes that were written to "buf" is returned (including the
|
|
|
|
terminating '\0'). */
|
|
|
|
|
|
|
|
ulint
|
|
|
|
row_raw_format(
|
|
|
|
/*===========*/
|
|
|
|
/* out: number of bytes
|
|
|
|
that were written */
|
|
|
|
const char* data, /* in: raw data */
|
|
|
|
ulint data_len, /* in: raw data length
|
|
|
|
in bytes */
|
|
|
|
const dict_field_t* dict_field, /* in: index field */
|
|
|
|
char* buf, /* out: output buffer */
|
|
|
|
ulint buf_size) /* in: output buffer size
|
|
|
|
in bytes */
|
|
|
|
{
|
|
|
|
ulint mtype;
|
|
|
|
ulint prtype;
|
|
|
|
ulint ret;
|
|
|
|
ibool format_in_hex;
|
|
|
|
|
|
|
|
if (buf_size == 0) {
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data_len == UNIV_SQL_NULL) {
|
|
|
|
|
|
|
|
ret = ut_snprintf((char*) buf, buf_size, "NULL") + 1;
|
|
|
|
|
|
|
|
return(ut_min(ret, buf_size));
|
|
|
|
}
|
|
|
|
|
|
|
|
mtype = dict_field->col->mtype;
|
|
|
|
prtype = dict_field->col->prtype;
|
|
|
|
|
|
|
|
format_in_hex = FALSE;
|
|
|
|
|
|
|
|
switch (mtype) {
|
|
|
|
case DATA_INT:
|
|
|
|
|
|
|
|
ret = row_raw_format_int(data, data_len, prtype,
|
|
|
|
buf, buf_size, &format_in_hex);
|
|
|
|
break;
|
|
|
|
case DATA_CHAR:
|
|
|
|
case DATA_VARCHAR:
|
|
|
|
case DATA_MYSQL:
|
|
|
|
case DATA_VARMYSQL:
|
|
|
|
|
|
|
|
ret = row_raw_format_str(data, data_len, prtype,
|
|
|
|
buf, buf_size, &format_in_hex);
|
|
|
|
break;
|
|
|
|
/* XXX support more data types */
|
|
|
|
default:
|
|
|
|
|
|
|
|
format_in_hex = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (format_in_hex) {
|
|
|
|
|
|
|
|
if (UNIV_LIKELY(buf_size > 2)) {
|
|
|
|
|
|
|
|
memcpy(buf, "0x", 2);
|
|
|
|
buf += 2;
|
|
|
|
buf_size -= 2;
|
2007-11-06 17:39:51 +01:00
|
|
|
ret = 2 + ut_raw_to_hex(data, data_len,
|
|
|
|
buf, buf_size);
|
2007-10-29 14:03:53 +01:00
|
|
|
} else {
|
|
|
|
|
|
|
|
buf[0] = '\0';
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* !UNIV_HOTBACKUP */
|
|
|
|
|
|
|
|
#ifdef UNIV_COMPILE_TEST_FUNCS
|
|
|
|
|
|
|
|
#include "ut0dbg.h"
|
|
|
|
|
|
|
|
void
|
|
|
|
test_row_raw_format_int()
|
|
|
|
{
|
|
|
|
ulint ret;
|
|
|
|
char buf[128];
|
|
|
|
ibool format_in_hex;
|
|
|
|
|
|
|
|
#define CALL_AND_TEST(data, data_len, prtype, buf, buf_size,\
|
|
|
|
ret_expected, buf_expected, format_in_hex_expected)\
|
|
|
|
do {\
|
|
|
|
ibool ok = TRUE;\
|
|
|
|
ulint i;\
|
|
|
|
memset(buf, 'x', 10);\
|
|
|
|
buf[10] = '\0';\
|
|
|
|
format_in_hex = FALSE;\
|
|
|
|
fprintf(stderr, "TESTING \"\\x");\
|
|
|
|
for (i = 0; i < data_len; i++) {\
|
|
|
|
fprintf(stderr, "%02hhX", data[i]);\
|
|
|
|
}\
|
|
|
|
fprintf(stderr, "\", %lu, %lu, %lu\n",\
|
|
|
|
(ulint) data_len, (ulint) prtype,\
|
|
|
|
(ulint) buf_size);\
|
|
|
|
ret = row_raw_format_int(data, data_len, prtype,\
|
|
|
|
buf, buf_size, &format_in_hex);\
|
|
|
|
if (ret != ret_expected) {\
|
|
|
|
fprintf(stderr, "expected ret %lu, got %lu\n",\
|
|
|
|
(ulint) ret_expected, ret);\
|
|
|
|
ok = FALSE;\
|
|
|
|
}\
|
|
|
|
if (strcmp((char*) buf, buf_expected) != 0) {\
|
|
|
|
fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
|
|
|
|
buf_expected, buf);\
|
|
|
|
ok = FALSE;\
|
|
|
|
}\
|
|
|
|
if (format_in_hex != format_in_hex_expected) {\
|
|
|
|
fprintf(stderr, "expected format_in_hex %d, got %d\n",\
|
|
|
|
(int) format_in_hex_expected,\
|
|
|
|
(int) format_in_hex);\
|
|
|
|
ok = FALSE;\
|
|
|
|
}\
|
|
|
|
if (ok) {\
|
|
|
|
fprintf(stderr, "OK: %lu, \"%s\" %d\n\n",\
|
|
|
|
(ulint) ret, buf, (int) format_in_hex);\
|
|
|
|
} else {\
|
|
|
|
return;\
|
|
|
|
}\
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
/* min values for signed 1-8 byte integers */
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00", 1, 0,
|
|
|
|
buf, sizeof(buf), 5, "-128", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00", 2, 0,
|
|
|
|
buf, sizeof(buf), 7, "-32768", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00", 3, 0,
|
|
|
|
buf, sizeof(buf), 9, "-8388608", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00", 4, 0,
|
|
|
|
buf, sizeof(buf), 12, "-2147483648", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, 0,
|
|
|
|
buf, sizeof(buf), 14, "-549755813888", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, 0,
|
|
|
|
buf, sizeof(buf), 17, "-140737488355328", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, 0,
|
|
|
|
buf, sizeof(buf), 19, "-36028797018963968", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, 0,
|
|
|
|
buf, sizeof(buf), 21, "-9223372036854775808", 0);
|
|
|
|
|
|
|
|
/* min values for unsigned 1-8 byte integers */
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00", 1, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 2, "0", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00", 2, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 2, "0", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00", 3, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 2, "0", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00", 4, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 2, "0", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 2, "0", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 2, "0", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 2, "0", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 2, "0", 0);
|
|
|
|
|
|
|
|
/* max values for signed 1-8 byte integers */
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF", 1, 0,
|
|
|
|
buf, sizeof(buf), 4, "127", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF", 2, 0,
|
|
|
|
buf, sizeof(buf), 6, "32767", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF", 3, 0,
|
|
|
|
buf, sizeof(buf), 8, "8388607", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, 0,
|
|
|
|
buf, sizeof(buf), 11, "2147483647", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, 0,
|
|
|
|
buf, sizeof(buf), 13, "549755813887", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, 0,
|
|
|
|
buf, sizeof(buf), 16, "140737488355327", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, 0,
|
|
|
|
buf, sizeof(buf), 18, "36028797018963967", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, 0,
|
|
|
|
buf, sizeof(buf), 20, "9223372036854775807", 0);
|
|
|
|
|
|
|
|
/* max values for unsigned 1-8 byte integers */
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF", 1, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 4, "255", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF", 2, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 6, "65535", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF", 3, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 9, "16777215", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 11, "4294967295", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 14, "1099511627775", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 16, "281474976710655", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 18, "72057594037927935", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 21, "18446744073709551615", 0);
|
|
|
|
|
|
|
|
/* some random values */
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x52", 1, 0,
|
|
|
|
buf, sizeof(buf), 4, "-46", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x0E", 1, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 3, "14", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x62\xCE", 2, 0,
|
|
|
|
buf, sizeof(buf), 6, "-7474", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x29\xD6", 2, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 6, "10710", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x7F\xFF\x90", 3, 0,
|
|
|
|
buf, sizeof(buf), 5, "-112", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\xA1\x16", 3, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 6, "41238", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x7F\xFF\xFF\xF7", 4, 0,
|
|
|
|
buf, sizeof(buf), 3, "-9", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x5C", 4, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 3, "92", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x7F\xFF\xFF\xFF\xFF\xFF\xDC\x63", 8, 0,
|
|
|
|
buf, sizeof(buf), 6, "-9117", 0);
|
|
|
|
|
|
|
|
CALL_AND_TEST("\x00\x00\x00\x00\x00\x01\x64\x62", 8, DATA_UNSIGNED,
|
|
|
|
buf, sizeof(buf), 6, "91234", 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* speed test */
|
|
|
|
|
|
|
|
speedo_t speedo;
|
|
|
|
ulint i;
|
|
|
|
|
|
|
|
speedo_reset(&speedo);
|
|
|
|
|
|
|
|
for (i = 0; i < 1000000; i++) {
|
|
|
|
row_raw_format_int("\x23", 1,
|
|
|
|
0, buf, sizeof(buf),
|
|
|
|
&format_in_hex);
|
|
|
|
row_raw_format_int("\x23", 1,
|
|
|
|
DATA_UNSIGNED, buf, sizeof(buf),
|
|
|
|
&format_in_hex);
|
|
|
|
|
|
|
|
row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
|
|
|
|
0, buf, sizeof(buf),
|
|
|
|
&format_in_hex);
|
|
|
|
row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
|
|
|
|
DATA_UNSIGNED, buf, sizeof(buf),
|
|
|
|
&format_in_hex);
|
|
|
|
}
|
|
|
|
|
|
|
|
speedo_show(&speedo);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* UNIV_COMPILE_TEST_FUNCS */
|