mariadb/row/row0row.c

1262 lines
33 KiB
C
Raw Normal View History

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
#include "data0type.h"
2005-10-27 09:29:40 +02:00
#include "dict0dict.h"
#include "btr0btr.h"
#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"
#include "row0ext.h"
2005-10-27 09:29:40 +02:00
#include "row0upd.h"
#include "rem0cmp.h"
#include "read0read.h"
#include "ut0mem.h"
2005-10-27 09:29:40 +02: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
ulint
row_get_trx_id_offset(
2005-10-27 09:29:40 +02:00
/*==================*/
/* out: offset of DATA_TRX_ID */
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;
ulint offset;
2005-10-27 09:29:40 +02:00
ulint len;
ut_ad(dict_index_is_clust(index));
2005-10-27 09:29:40 +02:00
ut_ad(rec_offs_validate(rec, index, offsets));
pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
2005-10-27 09:29:40 +02:00
offset = rec_get_nth_field_offs(offsets, pos, &len);
2005-10-27 09:29:40 +02:00
ut_ad(len == DATA_TRX_ID_LEN);
2005-10-27 09:29:40 +02:00
return(offset);
2005-10-27 09:29:40 +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(
/*==================*/
/* out: index entry which should be
inserted or purged, or NULL if the
externally stored columns in the
clustered index record are unavailable
and ext != NULL */
const dtuple_t* row, /* in: row which should be
inserted or purged */
row_ext_t* ext, /* in: externally stored column prefixes,
or NULL */
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));
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);
ut_a(!ext);
2005-10-27 09:29:40 +02:00
} else {
dtuple_set_n_fields_cmp(
entry, dict_index_get_n_unique_in_tree(index));
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++) {
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
= dfield_get_len(dfield2);
2005-10-27 09:29:40 +02:00
dfield_copy(dfield, dfield2);
if (UNIV_LIKELY_NULL(ext) && !dfield_is_null(dfield)) {
/* See if the column is stored externally. */
const byte* buf = row_ext_lookup(ext, col_no,
&len);
if (UNIV_LIKELY_NULL(buf)) {
if (UNIV_UNLIKELY(buf == field_ref_zero)) {
return(NULL);
}
dfield_set_data(dfield, buf, len);
}
}
2005-10-27 09:29:40 +02:00
/* If a column prefix index, take only the prefix */
if (ind_field->prefix_len > 0 && !dfield_is_null(dfield)) {
len = dtype_get_at_most_n_mbchars(
col->prtype, col->mbminlen, col->mbmaxlen,
ind_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(entry));
return(entry);
}
2005-10-27 09:29:40 +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(
/*======*/
/* 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
{
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];
rec_offs_init(offsets_);
2005-10-27 09:29:40 +02:00
ut_ad(index && rec && heap);
ut_ad(dict_index_is_clust(index));
2005-10-27 09:29:40 +02:00
if (!offsets) {
offsets = rec_get_offsets(rec, index, offsets_,
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);
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);
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);
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);
ulint col_no
= dict_col_get_no(col);
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
2007-10-17 14:13:29 +02:00
dfield_t* dfield
= dtuple_get_nth_field(row, col_no);
2005-10-27 09:29:40 +02:00
if (ind_field->prefix_len == 0) {
const byte* field = rec_get_nth_field(
rec, offsets, i, &len);
2005-10-27 09:29:40 +02:00
dfield_set_data(dfield, field, len);
}
if (rec_offs_nth_extern(offsets, i)) {
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
2007-10-17 14:13:29 +02:00
dfield_set_ext(dfield);
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);
}
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;
}
}
2005-10-27 09:29:40 +02:00
}
ut_ad(dtuple_check_typed(row));
if (j) {
*ext = row_ext_create(j, ext_cols, row,
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);
}
/***********************************************************************
Converts an index record to a typed data tuple. */
dtuple_t*
row_rec_to_index_entry_low(
/*=======================*/
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
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 */
{
dtuple_t* entry;
dfield_t* dfield;
ulint i;
const byte* field;
ulint len;
ulint rec_len;
ut_ad(rec && heap && index);
/* 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. */
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
2007-10-17 14:13:29 +02:00
ut_ad(n_ext);
*n_ext = 0;
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: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
2007-10-17 14:13:29 +02:00
if (rec_offs_nth_extern(offsets, i)) {
dfield_set_ext(dfield);
(*n_ext)++;
}
}
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(
/*===================*/
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of 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);
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
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);
}
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
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,
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 */
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
2007-10-17 14:13:29 +02:00
dict_index_t* index, /* in: secondary index */
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;
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_;
rec_offs_init(offsets_);
2005-10-27 09:29:40 +02:00
ut_ad(index && rec && heap);
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
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,
ULINT_UNDEFINED, &tmp_heap);
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
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;
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++) {
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);
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. */
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) {
if (len != UNIV_SQL_NULL) {
2005-10-27 09:29:40 +02:00
const dtype_t* dtype
= dfield_get_type(dfield);
2005-10-27 09:29:40 +02:00
dfield_set_len(dfield,
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(
/*=======================*/
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
{
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];
rec_offs_init(offsets_);
2005-10-27 09:29:40 +02:00
ut_a(ref);
ut_a(index);
ut_a(rec);
ut_ad(!dict_index_is_clust(index));
if (UNIV_UNLIKELY(!index->table)) {
2005-10-27 09:29:40 +02:00
fputs("InnoDB: table ", stderr);
notfound:
ut_print_name(stderr, trx, TRUE, index->table_name);
2005-10-27 09:29:40 +02:00
fputs(" for index ", stderr);
ut_print_name(stderr, trx, FALSE, index->name);
2005-10-27 09:29:40 +02:00
fputs(" not found\n", stderr);
ut_error;
}
2005-10-27 09:29:40 +02:00
clust_index = dict_table_get_first_index(index->table);
if (UNIV_UNLIKELY(!clust_index)) {
2005-10-27 09:29:40 +02:00
fputs("InnoDB: clust index for table ", stderr);
goto notfound;
}
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
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
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));
2005-10-27 09:29:40 +02:00
dict_index_copy_types(ref, clust_index, ref_len);
for (i = 0; i < ref_len; i++) {
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. */
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) {
if (len != UNIV_SQL_NULL) {
2005-10-27 09:29:40 +02:00
const dtype_t* dtype
= dfield_get_type(dfield);
2005-10-27 09:29:40 +02:00
dfield_set_len(dfield,
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(
/*=======================*/
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
{
const dict_index_t* clust_index;
ulint ref_len;
ulint i;
2005-10-27 09:29:40 +02:00
ut_ad(ref && table && row);
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));
2005-10-27 09:29:40 +02:00
for (i = 0; i < ref_len; i++) {
const dict_col_t* col;
const dict_field_t* field;
dfield_t* dfield;
const dfield_t* dfield2;
dfield = dtuple_get_nth_field(ref, i);
2005-10-27 09:29:40 +02:00
field = dict_index_get_nth_field(clust_index, i);
2005-10-27 09:29:40 +02:00
col = dict_field_get_col(field);
2005-10-27 09:29:40 +02:00
dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col));
dfield_copy(dfield, dfield2);
branches/zip: Initialize dfield_t::ext as soon as possible. This should fix the bugs introduced in r1591. row_rec_to_index_entry_low(): Clear "n_ext". Do not allow it to be NULL. Add const qualifier to dict_index_t*. row_rec_to_index_entry(): Add the parameters "offsets" and "n_ext". btr_cur_optimistic_update(): Add an assertion that there are no externally stored columns. Remove the unreachable call to btr_cur_unmark_extern_fields() and the preceding unnecessary call to rec_get_offsets(). btr_push_update_extern_fields(): Remove the parameters index, offsets. Only report the additional externally stored columns of the update vector. row_build(), trx_undo_rec_get_partial_row(): Flag externally stored columns also with dfield_set_ext(). rec_copy_prefix_to_dtuple(): Assert that there are no externally stored columns in the prefix. row_build_row_ref(): Note and assert that the index is a secondary index, and assert that there are no externally stored columns. row_build_row_ref_fast(): Assert that there are no externally stored columns. rec_offs_get_n_alloc(): Expose the function. row_build_row_ref_in_tuple(): Assert that there are no externally stored columns in a record of a secondary index. row_build_row_ref_from_row(): Assert that there are no externally stored columns. row_upd_check_references_constraints(): Add the parameter offsets, to avoid a redundant call to rec_get_offsets(). row_upd_del_mark_clust_rec(): Add the parameter offsets. Remove duplicated code. row_ins_index_entry_set_vals(): Copy the external storage flag. sel_pop_prefetched_row(): Assert that there are no externally stored columns. row_scan_and_check_index(): Copy offsets to a temporary heap across the invocation of row_rec_to_index_entry().
2007-10-17 14:13:29 +02:00
ut_ad(!dfield_is_ext(dfield));
2005-10-27 09:29:40 +02:00
if (field->prefix_len > 0 && !dfield_is_null(dfield)) {
2005-10-27 09:29:40 +02:00
ulint len = dfield_get_len(dfield);
len = dtype_get_at_most_n_mbchars(
col->prtype, col->mbminlen, col->mbmaxlen,
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(
/*==================*/
/* 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
{
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);
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, ... */
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;
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 */
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));
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);
return(!page_rec_is_infimum(rec) && low_match == n_fields);
2005-10-27 09:29:40 +02: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;
ret = 2 + ut_raw_to_hex(data, data_len,
buf, buf_size);
} 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 */