switch (dfield_get_spatial_status(dfield2)) { case SPATIAL_ONLY:
ut_ad(dfield_get_len(dfield2) == DATA_MBR_LEN); break;
case SPATIAL_MIXED:
ptr += dfield_get_len(dfield2); break;
case SPATIAL_UNKNOWN:
ut_ad(0); /* fall through */ case SPATIAL_NONE: /* Undo record is logged before
spatial index is created.*/ returnfalse;
}
memcpy(mbr, ptr, DATA_MBR_LEN); returntrue;
}
if (flag == ROW_BUILD_FOR_UNDO
&& dict_table_has_atomic_blobs(index->table)) { /* For ROW_FORMAT=DYNAMIC or COMPRESSED, a prefix of off-pagerecordsisstoredintheundologrecord(for anycolumnprefixindexes).ForSPATIALINDEX,we mustignorethisprefix.Thefullcolumnvalueis storedintheBLOB.Fornon-spatialindex,wewould havealreadyfetchedanecessaryprefixoftheBLOB, availableinthe"ext"parameter.
write_mbr: if (dlen <= GEO_DATA_HEADER_SIZE) { for (uint i = 0; i < 2 * SPDIMS; i += 2) {
tmp_mbr[i] = DBL_MAX;
tmp_mbr[i + 1] = -DBL_MAX;
}
} else {
rtree_mbr_from_wkb(dptr + GEO_DATA_HEADER_SIZE,
uint(dlen - GEO_DATA_HEADER_SIZE),
SPDIMS, tmp_mbr);
}
dfield_write_mbr(dfield, tmp_mbr); if (temp_heap) {
mem_heap_free(temp_heap);
}
returntrue;
}
/*****************************************************************//**
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.
@return index entry which should be inserted or purged
@retval NULL if the externally stored columns in the clustered index record
are unavailable and ext != NULL, or row is missing some needed columns. */
dtuple_t*
row_build_index_entry_low( /*======================*/ const dtuple_t* row, /*!< in: row which should be
inserted or purged */ const row_ext_t* ext, /*!< in: externally stored column
prefixes, or NULL */ const dict_index_t* index, /*!< in: index on the table */
mem_heap_t* heap, /*!< in,out: memory heap from which thememoryfortheindexentry
is allocated */
ulint flag) /*!< in: ROW_BUILD_NORMAL, ROW_BUILD_FOR_PURGE
or ROW_BUILD_FOR_UNDO */
{
dtuple_t* entry;
ulint entry_len;
ulint i = 0;
ulint num_v = 0;
dtuple_set_n_fields_cmp(entry, dict_index_get_n_unique_in_tree(index)); if (index->is_spatial()) { /* Set the MBR field */ if (!row_build_spatial_index_key(
index, ext,
dtuple_get_nth_field(entry, 0),
dtuple_get_nth_field(
row,
dict_index_get_nth_field(index, i)
->col->ind), flag, heap)) { return NULL;
}
i = 1;
}
for (; i < entry_len; i++) { const dict_field_t& f = index->fields[i];
dfield_t* dfield = dtuple_get_nth_field(entry, i);
if (f.col->is_dropped()) {
ut_ad(index->is_primary());
ut_ad(index->is_instant());
ut_ad(!f.col->is_virtual());
dict_col_copy_type(f.col, &dfield->type); if (f.col->is_nullable()) {
dfield_set_null(dfield); if (f.col->mtype == DATA_BINARY
&& !dict_table_is_comp(index->table)) { /* In case of redundant row format, ifthenon-fixeddroppedcolumn isnullthensetthelengthofthe
field data type as 0 */
dfield->type.len= 0;
}
} else {
dfield_set_data(dfield, field_ref_zero,
f.fixed_len);
} continue;
}
const dfield_t* dfield2;
if (f.col->is_virtual()) { const dict_v_col_t* v_col
= reinterpret_cast<const dict_v_col_t*>(f.col);
ut_ad(dfield_is_null(dfield2) ||
dfield_get_len(dfield2) == 0 || dfield2->data);
ut_ad(!dfield_is_ext(dfield2)); if (UNIV_UNLIKELY(dfield2->type.mtype
== DATA_MISSING)) {
ut_ad(flag == ROW_BUILD_FOR_PURGE); return(NULL);
}
} else {
dfield2 = dtuple_get_nth_field(row, f.col->ind); if (UNIV_UNLIKELY(dfield2->type.mtype
== DATA_MISSING)) { /* The field has not been initialized in therow.Thisshouldbefrom
trx_undo_rec_get_partial_row(). */ return(NULL);
}
ut_ad(!(dfield2->type.prtype & DATA_VIRTUAL));
}
compile_time_assert(DATA_MISSING == 0);
*dfield = *dfield2;
if (dfield_is_null(dfield)) { continue;
}
ut_ad(!(index->type & DICT_FTS));
ulint len = dfield_get_len(dfield);
if (f.prefix_len == 0
&& (!dfield_is_ext(dfield)
|| dict_index_is_clust(index))) { /* The *dfield = *dfield2 above suffices for columnsthatarestoredin-page,orfor clusteredindexrecordcolumnsthatarenot
part of a column prefix in the PRIMARY KEY. */ continue;
}
/* If the column is stored externally (off-page) in theclusteredindex,itmustbeanorderingfieldin thesecondaryindex.If!atomic_blobs,theonlyway wemayhaveasecondaryindexpointingtoaclustered indexrecordwithanoff-pagecolumniswhenitisa columnprefixindex.Ifatomic_blobs,alsofully
indexed long columns may be stored off-page. */
ut_ad(f.col->ord_part);
if (ext && !f.col->is_virtual()) { /* See if the column is stored externally. */ const byte* buf = row_ext_lookup(ext, f.col->ind,
&len); if (UNIV_LIKELY_NULL(buf)) { if (UNIV_UNLIKELY(buf == field_ref_zero)) { return(NULL);
}
dfield_set_data(dfield, buf, len);
}
if (f.prefix_len == 0) { /* If ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED,wecanhavea secondaryindexonanentirecolumn thatisstoredoff-pageinthe clusteredindex.Asthisisnota prefixindex(prefix_len==0), includetheentireoff-pagecolumnin
the secondary index record. */ continue;
}
} elseif (dfield_is_ext(dfield)) { /* This table is either in (ROW_FORMAT=REDUNDANTorROW_FORMAT=COMPACT) orapurgerecordwheretheorderedpartof thefieldisnotexternal. InROW_FORMAT=REDUNDANTandROW_FORMAT=COMPACT, themaximumcolumnprefix indexlengthis767bytes,andtheclustered indexrecordcontainsa768-byteprefixof
each off-page column. */
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
len -= BTR_EXTERN_FIELD_REF_SIZE;
dfield_set_len(dfield, len);
}
/* If a column prefix index, take only the prefix. */ if (f.prefix_len) {
len = dtype_get_at_most_n_mbchars(
f.col->prtype,
f.col->mbminlen, f.col->mbmaxlen,
f.prefix_len, len, static_cast<char*>(dfield_get_data(dfield)));
dfield_set_len(dfield, len);
}
}
for (ulint i = 0; i < rec_offs_n_fields(offsets); i++) { if (i == index->first_user_field()
&& rec_is_alter_metadata(rec, *index)) {
ut_ad(rec_offs_nth_extern(offsets, i));
ut_d(ulint len);
ut_d(rec_get_nth_field_offs(offsets, i, &len));
ut_ad(len == FIELD_REF_SIZE); continue;
}
if (UNIV_UNLIKELY(ind_field
>= &index->fields[index->n_fields])) {
ut_ad(rec_is_metadata(rec, *index)); continue;
}
const dict_col_t* col = dict_field_get_col(ind_field);
if ((ind_field++)->prefix_len) { /* Column prefixes can only occur in key fields,whichcannotbestoredexternally.For acolumnprefix,thereshouldalsobethefull fieldintheclusteredindextuple.Therow
tuple comprises full fields, not prefixes. */
ut_ad(!rec_offs_nth_extern(offsets, i)); continue;
}
constvoid* field = rec_get_nth_field(
copy, offsets, i, &len); if (len == UNIV_SQL_DEFAULT) {
field = index->instant_field_value(i, &len); if (field && type != ROW_COPY_POINTERS) {
field = mem_heap_dup(heap, field, len);
}
}
dfield_set_data(dfield, field, len);
if (rec_offs_nth_extern(offsets, i)) {
dfield_set_ext(dfield);
col = dict_table_get_nth_col(col_table, col_no);
if (col->ord_part) { /* We will have to fetch prefixes of externallystoredcolumnsthatare
referenced by column prefixes. */
ext_cols[j++] = col_no;
}
}
}
/*******************************************************************//**
An inverse function to row_build_index_entry. Builds a row from a
record in a clustered index.
@return own: row built; see the NOTE below! */
dtuple_t*
row_build( /*======*/
ulint type, /*!< in: ROW_COPY_POINTERS or ROW_COPY_DATA;thelatter copiesalsothedatafieldsto heapwhilethefirstonly placespointerstodatafields ontheindexpage,andthusis
more efficient */ const dict_index_t* index, /*!< in: clustered index */ const rec_t* rec, /*!< in: record in the clustered index;NOTE:inthecase ROW_COPY_POINTERSthedata fieldsintherowwillpoint directlyintothisrecord, therefore,thebufferpageof thisrecordmustbeatleast s-latchedandthelatchheld
as long as the row dtuple is used! */ const rec_offs* offsets,/*!< in: rec_get_offsets(rec,index) orNULL,inwhichcasethisfunction
will invoke rec_get_offsets() */ const dict_table_t* col_table, /*!< in: table, to check which externallystoredcolumns occurintheorderingcolumns ofanindex,orNULLif index->tableshouldbe
consulted instead */ const dtuple_t* defaults, /*!< in: default values of
added and changed columns, or NULL */ const ulint* col_map,/*!< in: mapping of old column
numbers to new ones, or NULL */
row_ext_t** ext, /*!< out, own: cache of externallystoredcolumn
prefixes, or NULL */
mem_heap_t* heap) /*!< in: memory heap from which
the memory needed is allocated */
{ return(row_build_low(type, index, rec, offsets, col_table,
defaults, NULL, col_map, ext, heap));
}
/** Convert an index record to a data tuple. @tparammetadatawhethertheindex->instant_field_value()needstobeaccessed @tparammblob1ifrec_is_alter_metadata(); 2ifwewantconvertedmetadatacorrespondingtoinfo_bits @param[in]recindexrecord @param[in]indexindex @param[in]offsetsrec_get_offsets(rec,index) @param[out]n_extnumberofexternallystoredcolumns @param[in,out]heapmemoryheapforallocations @param[in]info_bits(onlyusedifmblob=2) @param[in]pad(onlyusedifmblob=2) @returnindexentrybuilt;doesnotsetinfo_bits,andthedatafields
in the entry will point directly to rec */ template<bool metadata, int mblob = 0> staticinline
dtuple_t*
row_rec_to_index_entry_impl( const rec_t* rec, const dict_index_t* index, const rec_offs* offsets,
mem_heap_t* heap,
ulint info_bits = 0, bool pad = false)
{
ut_ad(rec != NULL);
ut_ad(heap != NULL);
ut_ad(index != NULL);
ut_ad(!mblob || index->is_primary());
ut_ad(!mblob || !index->table->is_temporary());
ut_ad(!mblob || !dict_index_is_spatial(index));
compile_time_assert(!mblob || metadata);
compile_time_assert(mblob <= 2); /* Because this function may be invoked by row0merge.cc onarecordwhoseheaderisindifferentformat,thecheck
rec_offs_validate(rec, index, offsets) must be avoided here. */
if (mblob == 2) { constbool want = info_bits == REC_INFO_METADATA_ALTER; if (got == want) { if (got) { goto copy_metadata;
}
} else { if (want) { /* Allocate a placeholder for
adding metadata in an update. */
len = FIELD_REF_SIZE;
field = static_cast<byte*>(
mem_heap_zalloc(heap, len)); /* In reality there is one fewer
field present in the record. */
rec_len--; goto init_metadata;
}
/* Skip the undesired metadata blob (forexample,whenrollingbackan
instant ALTER TABLE). */
i++;
} goto copy_user_fields;
}
copy_metadata:
ut_ad(rec_offs_nth_extern(offsets, i));
field = rec_get_nth_field(rec, offsets, i++, &len);
init_metadata:
dfield->type.metadata_blob_init();
ut_ad(len == FIELD_REF_SIZE);
dfield_set_data(dfield, field, len);
dfield_set_ext(dfield++);
copy_user_fields: for (; i < rec_len; i++, dfield++) {
dict_col_copy_type(dict_index_get_nth_col(index, j++),
&dfield->type); if (mblob == 2 && pad
&& i >= rec_offs_n_fields(offsets)) {
field = index->instant_field_value(j - 1,
&len);
dfield_set_data(dfield, field, len); continue;
}
field = rec_get_nth_field(rec, offsets, i, &len);
dfield_set_data(dfield, field, len);
if (rec_offs_nth_extern(offsets, i)) {
dfield_set_ext(dfield);
}
}
}
/** Convert an index record to a data tuple. @param[in]recindexrecord @param[in]indexindex @param[in]offsetsrec_get_offsets(rec,index)
@param[in,out] heap memory heap for allocations */
dtuple_t*
row_rec_to_index_entry_low( const rec_t* rec, const dict_index_t* index, const rec_offs* offsets,
mem_heap_t* heap)
{ return row_rec_to_index_entry_impl<false>(rec, index, offsets, heap);
}
/*******************************************************************//**
Converts an index record to a typed data tuple. NOTE that externally
stored (often big) fields are NOT copied to heap.
@return own: index entry built */
dtuple_t*
row_rec_to_index_entry( /*===================*/ const rec_t* rec, /*!< in: record in the index */ const dict_index_t* index, /*!< in: index */ const rec_offs* offsets,/*!< in: rec_get_offsets(rec) */
mem_heap_t* heap) /*!< in: memory heap from which
the memory needed is allocated */
{
ut_ad(rec != NULL);
ut_ad(heap != NULL);
ut_ad(index != NULL);
ut_ad(rec_offs_validate(rec, index, offsets));
/* Take a copy of rec to heap */ const rec_t* copy_rec = rec_copy( static_cast<byte*>(mem_heap_alloc(heap,
rec_offs_size(offsets))),
rec, offsets);
/*******************************************************************//**
Builds from a secondary index record a row reference with which we can
search the clustered index record.
@return own: row reference built; see the NOTE below! */
dtuple_t*
row_build_row_ref( /*==============*/
ulint type, /*!< in: ROW_COPY_DATA, or ROW_COPY_POINTERS: theformercopiesalsothedatafieldsto heap,whereasthelatteronlyplacespointers
to data fields on the index page */
dict_index_t* index, /*!< in: secondary index */ const rec_t* rec, /*!< in: record in the index; NOTE:inthecaseROW_COPY_POINTERS thedatafieldsintherowwillpoint directlyintothisrecord,therefore, thebufferpageofthisrecordmustbe atleasts-latchedandthelatchheld
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;
ulint len;
ulint ref_len;
ulint pos;
byte* buf;
ulint clust_col_prefix_len;
ulint i;
mem_heap_t* tmp_heap = NULL;
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
rec_offs* offsets = offsets_;
rec_offs_init(offsets_);
ut_ad(!rec_offs_nth_default(offsets, pos));
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 secondaryindexmaycontainalongerprefixofthesame column,orthefullcolumn,andwemustadjustthelength
accordingly. */
ut_ad(!rec_offs_nth_default(offsets, pos));
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 secondaryindexmaycontainalongerprefixofthesame column,orthefullcolumn,andwemustadjustthelength
accordingly. */
ut_ad(dtuple_check_typed(ref)); if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
/***************************************************************//**
Searches the clustered index record for a row, if we have the row reference.
@returnTRUEif found */ bool
row_search_on_row_ref( /*==================*/
btr_pcur_t* pcur, /*!< out: persistent cursor, which must
be closed by the caller */
btr_latch_mode 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 */
{
ut_ad(dtuple_check_typed(ref));
/*********************************************************************//**
Fetches the clustered index record for a secondary index record. The latches
on the secondary index record are preserved.
@return record or NULL, if no record found */
rec_t*
row_get_clust_rec( /*==============*/
btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */ const rec_t* rec, /*!< in: record in a secondary index */
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;
auto found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
mem_heap_free(heap);
*clust_index = dict_table_get_first_index(table); return found ? btr_pcur_get_rec(&pcur) : nullptr;
}
/***************************************************************//**
Searches an index record.
@return whether the record was found */ bool
row_search_index_entry( /*===================*/ const dtuple_t* entry, /*!< in: index entry */
btr_latch_mode 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 */
{
ut_ad(dtuple_check_typed(entry));
/*******************************************************************//**
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').
@return number of bytes that were written */ static
ulint
row_raw_format_int( /*===============*/ constchar* 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
formatted in hex */
{
ulint ret;
/*******************************************************************//**
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').
@return number of bytes that were written */ static
ulint
row_raw_format_str( /*===============*/ constchar* 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
formatted in hex */
{
ulint charset_coll;
/*******************************************************************//**
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 NUL-terminated (provided buf_size is positive) and the
number of bytes that were written to "buf" is returned (including the
terminating NUL).
@return number of bytes that were written */
ulint
row_raw_format( /*===========*/ constchar* 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;
ut_ad(data_len != UNIV_SQL_DEFAULT);
if (buf_size == 0) {
return(0);
}
if (data_len == UNIV_SQL_NULL) {
ret = snprintf((char*) buf, buf_size, "NULL") + 1;
ret = row_raw_format_int(data, data_len, prtype,
buf, buf_size, &format_in_hex); if (format_in_hex) {
goto format_in_hex;
} break; case DATA_CHAR: case DATA_VARCHAR: /* FTS_%_CONFIG.key are incorrectly created with prtype==0. TheDATA_ENGLISHisbeingusedforCHARcolumnsofthe InnoDBinternalSQLparser,suchasSYS_FOREIGN.ID.
For these, we will eventually goto format_in_hex. */
ut_ad(dtype_get_charset_coll(prtype) == 8
|| (mtype == DATA_VARCHAR
&& (prtype == 0 || prtype == DATA_ENGLISH))); goto format_str; case DATA_MYSQL: case DATA_VARMYSQL:
ut_ad(dtype_get_charset_coll(prtype));
format_str:
ret = row_raw_format_str(data, data_len, prtype,
buf, buf_size, &format_in_hex); if (format_in_hex) {
goto format_in_hex;
}
break; /* XXX support more data types */ default:
format_in_hex:
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.