Drizzled Public API Documentation

rem0rec.cc

00001 /*****************************************************************************
00002 
00003 Copyright (C) 1994, 2010, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
00016 
00017 *****************************************************************************/
00018 
00019 /********************************************************************/
00026 #include "rem0rec.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "rem0rec.ic"
00030 #endif
00031 
00032 #include "mtr0mtr.h"
00033 #include "mtr0log.h"
00034 
00035 /*      PHYSICAL RECORD (OLD STYLE)
00036       ===========================
00037 
00038 The physical record, which is the data type of all the records
00039 found in index pages of the database, has the following format
00040 (lower addresses and more significant bits inside a byte are below
00041 represented on a higher text line):
00042 
00043 | offset of the end of the last field of data, the most significant
00044   bit is set to 1 if and only if the field is SQL-null,
00045   if the offset is 2-byte, then the second most significant
00046   bit is set to 1 if the field is stored on another page:
00047   mostly this will occur in the case of big BLOB fields |
00048 ...
00049 | offset of the end of the first field of data + the SQL-null bit |
00050 | 4 bits used to delete mark a record, and mark a predefined
00051   minimum record in alphabetical order |
00052 | 4 bits giving the number of records owned by this record
00053   (this term is explained in page0page.h) |
00054 | 13 bits giving the order number of this record in the
00055   heap of the index page |
00056 | 10 bits giving the number of fields in this record |
00057 | 1 bit which is set to 1 if the offsets above are given in
00058   one byte format, 0 if in two byte format |
00059 | two bytes giving an absolute pointer to the next record in the page |
00060 ORIGIN of the record
00061 | first field of data |
00062 ...
00063 | last field of data |
00064 
00065 The origin of the record is the start address of the first field
00066 of data. The offsets are given relative to the origin.
00067 The offsets of the data fields are stored in an inverted
00068 order because then the offset of the first fields are near the
00069 origin, giving maybe a better processor cache hit rate in searches.
00070 
00071 The offsets of the data fields are given as one-byte
00072 (if there are less than 127 bytes of data in the record)
00073 or two-byte unsigned integers. The most significant bit
00074 is not part of the offset, instead it indicates the SQL-null
00075 if the bit is set to 1. */
00076 
00077 /*      PHYSICAL RECORD (NEW STYLE)
00078       ===========================
00079 
00080 The physical record, which is the data type of all the records
00081 found in index pages of the database, has the following format
00082 (lower addresses and more significant bits inside a byte are below
00083 represented on a higher text line):
00084 
00085 | length of the last non-null variable-length field of data:
00086   if the maximum length is 255, one byte; otherwise,
00087   0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
00088   length=128..16383, extern storage flag) |
00089 ...
00090 | length of first variable-length field of data |
00091 | SQL-null flags (1 bit per nullable field), padded to full bytes |
00092 | 4 bits used to delete mark a record, and mark a predefined
00093   minimum record in alphabetical order |
00094 | 4 bits giving the number of records owned by this record
00095   (this term is explained in page0page.h) |
00096 | 13 bits giving the order number of this record in the
00097   heap of the index page |
00098 | 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
00099   010=infimum, 011=supremum, 1xx=reserved |
00100 | two bytes giving a relative pointer to the next record in the page |
00101 ORIGIN of the record
00102 | first field of data |
00103 ...
00104 | last field of data |
00105 
00106 The origin of the record is the start address of the first field
00107 of data. The offsets are given relative to the origin.
00108 The offsets of the data fields are stored in an inverted
00109 order because then the offset of the first fields are near the
00110 origin, giving maybe a better processor cache hit rate in searches.
00111 
00112 The offsets of the data fields are given as one-byte
00113 (if there are less than 127 bytes of data in the record)
00114 or two-byte unsigned integers. The most significant bit
00115 is not part of the offset, instead it indicates the SQL-null
00116 if the bit is set to 1. */
00117 
00118 /* CANONICAL COORDINATES. A record can be seen as a single
00119 string of 'characters' in the following way: catenate the bytes
00120 in each field, in the order of fields. An SQL-null field
00121 is taken to be an empty sequence of bytes. Then after
00122 the position of each field insert in the string
00123 the 'character' <FIELD-END>, except that after an SQL-null field
00124 insert <NULL-FIELD-END>. Now the ordinal position of each
00125 byte in this canonical string is its canonical coordinate.
00126 So, for the record ("AA", SQL-NULL, "BB", ""), the canonical
00127 string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>".
00128 We identify prefixes (= initial segments) of a record
00129 with prefixes of the canonical string. The canonical
00130 length of the prefix is the length of the corresponding
00131 prefix of the canonical string. The canonical length of
00132 a record is the length of its canonical string.
00133 
00134 For example, the maximal common prefix of records
00135 ("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C")
00136 is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical
00137 length is 5.
00138 
00139 A complete-field prefix of a record is a prefix which ends at the
00140 end of some field (containing also <FIELD-END>).
00141 A record is a complete-field prefix of another record, if
00142 the corresponding canonical strings have the same property. */
00143 
00144 /* this is used to fool compiler in rec_validate */
00145 UNIV_INTERN ulint rec_dummy;
00146 
00147 /***************************************************************/
00150 static
00151 ibool
00152 rec_validate_old(
00153 /*=============*/
00154   const rec_t*  rec); 
00156 /******************************************************/
00160 UNIV_INTERN
00161 ulint
00162 rec_get_n_extern_new(
00163 /*=================*/
00164   const rec_t*  rec,  
00165   dict_index_t* index,  
00166   ulint   n)  
00167 {
00168   const byte* nulls;
00169   const byte* lens;
00170   dict_field_t* field;
00171   ulint   null_mask;
00172   ulint   n_extern;
00173   ulint   i;
00174 
00175   ut_ad(dict_table_is_comp(index->table));
00176   ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
00177   ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
00178 
00179   if (n == ULINT_UNDEFINED) {
00180     n = dict_index_get_n_fields(index);
00181   }
00182 
00183   nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
00184   lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
00185   null_mask = 1;
00186   n_extern = 0;
00187   i = 0;
00188 
00189   /* read the lengths of fields 0..n */
00190   do {
00191     ulint len;
00192 
00193     field = dict_index_get_nth_field(index, i);
00194     if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
00195       /* nullable field => read the null flag */
00196 
00197       if (UNIV_UNLIKELY(!(byte) null_mask)) {
00198         nulls--;
00199         null_mask = 1;
00200       }
00201 
00202       if (*nulls & null_mask) {
00203         null_mask <<= 1;
00204         /* No length is stored for NULL fields. */
00205         continue;
00206       }
00207       null_mask <<= 1;
00208     }
00209 
00210     if (UNIV_UNLIKELY(!field->fixed_len)) {
00211       /* Variable-length field: read the length */
00212       const dict_col_t* col
00213         = dict_field_get_col(field);
00214       len = *lens--;
00215       /* If the maximum length of the field is up
00216       to 255 bytes, the actual length is always
00217       stored in one byte. If the maximum length is
00218       more than 255 bytes, the actual length is
00219       stored in one byte for 0..127.  The length
00220       will be encoded in two bytes when it is 128 or
00221       more, or when the field is stored externally. */
00222       if (UNIV_UNLIKELY(col->len > 255)
00223           || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
00224         if (len & 0x80) {
00225           /* 1exxxxxxx xxxxxxxx */
00226           if (len & 0x40) {
00227             n_extern++;
00228           }
00229           lens--;
00230         }
00231       }
00232     }
00233   } while (++i < n);
00234 
00235   return(n_extern);
00236 }
00237 
00238 /******************************************************/
00242 UNIV_INTERN
00243 void
00244 rec_init_offsets_comp_ordinary(
00245 /*===========================*/
00246   const rec_t*    rec,  
00248   ulint     extra,  
00252   const dict_index_t* index,  
00253   ulint*      offsets)
00255 {
00256   ulint   i   = 0;
00257   ulint   offs    = 0;
00258   ulint   any_ext   = 0;
00259   const byte* nulls   = rec - (extra + 1);
00260   const byte* lens    = nulls
00261     - UT_BITS_IN_BYTES(index->n_nullable);
00262   dict_field_t* field;
00263   ulint   null_mask = 1;
00264 
00265 #ifdef UNIV_DEBUG
00266   /* We cannot invoke rec_offs_make_valid() here, because it can hold
00267   that extra != REC_N_NEW_EXTRA_BYTES.  Similarly, rec_offs_validate()
00268   will fail in that case, because it invokes rec_get_status(). */
00269   offsets[2] = (ulint) rec;
00270   offsets[3] = (ulint) index;
00271 #endif /* UNIV_DEBUG */
00272 
00273   /* read the lengths of fields 0..n */
00274   do {
00275     ulint len;
00276 
00277     field = dict_index_get_nth_field(index, i);
00278     if (!(dict_field_get_col(field)->prtype
00279           & DATA_NOT_NULL)) {
00280       /* nullable field => read the null flag */
00281 
00282       if (UNIV_UNLIKELY(!(byte) null_mask)) {
00283         nulls--;
00284         null_mask = 1;
00285       }
00286 
00287       if (*nulls & null_mask) {
00288         null_mask <<= 1;
00289         /* No length is stored for NULL fields.
00290         We do not advance offs, and we set
00291         the length to zero and enable the
00292         SQL NULL flag in offsets[]. */
00293         len = offs | REC_OFFS_SQL_NULL;
00294         goto resolved;
00295       }
00296       null_mask <<= 1;
00297     }
00298 
00299     if (UNIV_UNLIKELY(!field->fixed_len)) {
00300       /* Variable-length field: read the length */
00301       const dict_col_t* col
00302         = dict_field_get_col(field);
00303       len = *lens--;
00304       /* If the maximum length of the field is up
00305       to 255 bytes, the actual length is always
00306       stored in one byte. If the maximum length is
00307       more than 255 bytes, the actual length is
00308       stored in one byte for 0..127.  The length
00309       will be encoded in two bytes when it is 128 or
00310       more, or when the field is stored externally. */
00311       if (UNIV_UNLIKELY(col->len > 255)
00312           || UNIV_UNLIKELY(col->mtype
00313                == DATA_BLOB)) {
00314         if (len & 0x80) {
00315           /* 1exxxxxxx xxxxxxxx */
00316           len <<= 8;
00317           len |= *lens--;
00318 
00319           offs += len & 0x3fff;
00320           if (UNIV_UNLIKELY(len
00321                 & 0x4000)) {
00322             ut_ad(dict_index_is_clust
00323                   (index));
00324             any_ext = REC_OFFS_EXTERNAL;
00325             len = offs
00326               | REC_OFFS_EXTERNAL;
00327           } else {
00328             len = offs;
00329           }
00330 
00331           goto resolved;
00332         }
00333       }
00334 
00335       len = offs += len;
00336     } else {
00337       len = offs += field->fixed_len;
00338     }
00339 resolved:
00340     rec_offs_base(offsets)[i + 1] = len;
00341   } while (++i < rec_offs_n_fields(offsets));
00342 
00343   *rec_offs_base(offsets)
00344     = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
00345 }
00346 
00347 /******************************************************/
00361 static
00362 void
00363 rec_init_offsets(
00364 /*=============*/
00365   const rec_t*    rec,  
00366   const dict_index_t* index,  
00367   ulint*      offsets)
00369 {
00370   ulint i = 0;
00371   ulint offs;
00372 
00373   rec_offs_make_valid(rec, index, offsets);
00374 
00375   if (dict_table_is_comp(index->table)) {
00376     const byte* nulls;
00377     const byte* lens;
00378     dict_field_t* field;
00379     ulint   null_mask;
00380     ulint   status = rec_get_status(rec);
00381     ulint   n_node_ptr_field = ULINT_UNDEFINED;
00382 
00383     switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
00384     case REC_STATUS_INFIMUM:
00385     case REC_STATUS_SUPREMUM:
00386       /* the field is 8 bytes long */
00387       rec_offs_base(offsets)[0]
00388         = REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
00389       rec_offs_base(offsets)[1] = 8;
00390       return;
00391     case REC_STATUS_NODE_PTR:
00392       n_node_ptr_field
00393         = dict_index_get_n_unique_in_tree(index);
00394       break;
00395     case REC_STATUS_ORDINARY:
00396       rec_init_offsets_comp_ordinary(rec,
00397                    REC_N_NEW_EXTRA_BYTES,
00398                    index, offsets);
00399       return;
00400     }
00401 
00402     nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
00403     lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
00404     offs = 0;
00405     null_mask = 1;
00406 
00407     /* read the lengths of fields 0..n */
00408     do {
00409       ulint len;
00410       if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
00411         len = offs += 4;
00412         goto resolved;
00413       }
00414 
00415       field = dict_index_get_nth_field(index, i);
00416       if (!(dict_field_get_col(field)->prtype
00417             & DATA_NOT_NULL)) {
00418         /* nullable field => read the null flag */
00419 
00420         if (UNIV_UNLIKELY(!(byte) null_mask)) {
00421           nulls--;
00422           null_mask = 1;
00423         }
00424 
00425         if (*nulls & null_mask) {
00426           null_mask <<= 1;
00427           /* No length is stored for NULL fields.
00428           We do not advance offs, and we set
00429           the length to zero and enable the
00430           SQL NULL flag in offsets[]. */
00431           len = offs | REC_OFFS_SQL_NULL;
00432           goto resolved;
00433         }
00434         null_mask <<= 1;
00435       }
00436 
00437       if (UNIV_UNLIKELY(!field->fixed_len)) {
00438         /* Variable-length field: read the length */
00439         const dict_col_t* col
00440           = dict_field_get_col(field);
00441         len = *lens--;
00442         /* If the maximum length of the field
00443         is up to 255 bytes, the actual length
00444         is always stored in one byte. If the
00445         maximum length is more than 255 bytes,
00446         the actual length is stored in one
00447         byte for 0..127.  The length will be
00448         encoded in two bytes when it is 128 or
00449         more, or when the field is stored
00450         externally. */
00451         if (UNIV_UNLIKELY(col->len > 255)
00452             || UNIV_UNLIKELY(col->mtype
00453                  == DATA_BLOB)) {
00454           if (len & 0x80) {
00455             /* 1exxxxxxx xxxxxxxx */
00456 
00457             len <<= 8;
00458             len |= *lens--;
00459 
00460             /* B-tree node pointers
00461             must not contain externally
00462             stored columns.  Thus
00463             the "e" flag must be 0. */
00464             ut_a(!(len & 0x4000));
00465             offs += len & 0x3fff;
00466             len = offs;
00467 
00468             goto resolved;
00469           }
00470         }
00471 
00472         len = offs += len;
00473       } else {
00474         len = offs += field->fixed_len;
00475       }
00476 resolved:
00477       rec_offs_base(offsets)[i + 1] = len;
00478     } while (++i < rec_offs_n_fields(offsets));
00479 
00480     *rec_offs_base(offsets)
00481       = (rec - (lens + 1)) | REC_OFFS_COMPACT;
00482   } else {
00483     /* Old-style record: determine extra size and end offsets */
00484     offs = REC_N_OLD_EXTRA_BYTES;
00485     if (rec_get_1byte_offs_flag(rec)) {
00486       offs += rec_offs_n_fields(offsets);
00487       *rec_offs_base(offsets) = offs;
00488       /* Determine offsets to fields */
00489       do {
00490         offs = rec_1_get_field_end_info(rec, i);
00491         if (offs & REC_1BYTE_SQL_NULL_MASK) {
00492           offs &= ~REC_1BYTE_SQL_NULL_MASK;
00493           offs |= REC_OFFS_SQL_NULL;
00494         }
00495         rec_offs_base(offsets)[1 + i] = offs;
00496       } while (++i < rec_offs_n_fields(offsets));
00497     } else {
00498       offs += 2 * rec_offs_n_fields(offsets);
00499       *rec_offs_base(offsets) = offs;
00500       /* Determine offsets to fields */
00501       do {
00502         offs = rec_2_get_field_end_info(rec, i);
00503         if (offs & REC_2BYTE_SQL_NULL_MASK) {
00504           offs &= ~REC_2BYTE_SQL_NULL_MASK;
00505           offs |= REC_OFFS_SQL_NULL;
00506         }
00507         if (offs & REC_2BYTE_EXTERN_MASK) {
00508           offs &= ~REC_2BYTE_EXTERN_MASK;
00509           offs |= REC_OFFS_EXTERNAL;
00510           *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
00511         }
00512         rec_offs_base(offsets)[1 + i] = offs;
00513       } while (++i < rec_offs_n_fields(offsets));
00514     }
00515   }
00516 }
00517 
00518 /******************************************************/
00522 UNIV_INTERN
00523 ulint*
00524 rec_get_offsets_func(
00525 /*=================*/
00526   const rec_t*    rec,  
00527   const dict_index_t* index,  
00528   ulint*      offsets,
00532   ulint     n_fields,
00535   mem_heap_t**    heap, 
00536   const char*   file, 
00537   ulint     line) 
00538 {
00539   ulint n;
00540   ulint size;
00541 
00542   ut_ad(rec);
00543   ut_ad(index);
00544   ut_ad(heap);
00545 
00546   if (dict_table_is_comp(index->table)) {
00547     switch (UNIV_EXPECT(rec_get_status(rec),
00548             REC_STATUS_ORDINARY)) {
00549     case REC_STATUS_ORDINARY:
00550       n = dict_index_get_n_fields(index);
00551       break;
00552     case REC_STATUS_NODE_PTR:
00553       n = dict_index_get_n_unique_in_tree(index) + 1;
00554       break;
00555     case REC_STATUS_INFIMUM:
00556     case REC_STATUS_SUPREMUM:
00557       /* infimum or supremum record */
00558       n = 1;
00559       break;
00560     default:
00561       ut_error;
00562       return(NULL);
00563     }
00564   } else {
00565     n = rec_get_n_fields_old(rec);
00566   }
00567 
00568   if (UNIV_UNLIKELY(n_fields < n)) {
00569     n = n_fields;
00570   }
00571 
00572   size = n + (1 + REC_OFFS_HEADER_SIZE);
00573 
00574   if (UNIV_UNLIKELY(!offsets)
00575       || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
00576     if (UNIV_UNLIKELY(!*heap)) {
00577       *heap = mem_heap_create_func(size * sizeof(ulint),
00578                  MEM_HEAP_DYNAMIC,
00579                  file, line);
00580     }
00581     offsets = static_cast<unsigned long *>(mem_heap_alloc(*heap, size * sizeof(ulint)));
00582     rec_offs_set_n_alloc(offsets, size);
00583   }
00584 
00585   rec_offs_set_n_fields(offsets, n);
00586   rec_init_offsets(rec, index, offsets);
00587   return(offsets);
00588 }
00589 
00590 /******************************************************/
00593 UNIV_INTERN
00594 void
00595 rec_get_offsets_reverse(
00596 /*====================*/
00597   const byte*   extra,  
00601   const dict_index_t* index,  
00602   ulint     node_ptr,
00604   ulint*      offsets)
00606 {
00607   ulint   n;
00608   ulint   i;
00609   ulint   offs;
00610   ulint   any_ext;
00611   const byte* nulls;
00612   const byte* lens;
00613   dict_field_t* field;
00614   ulint   null_mask;
00615   ulint   n_node_ptr_field;
00616 
00617   ut_ad(extra);
00618   ut_ad(index);
00619   ut_ad(offsets);
00620   ut_ad(dict_table_is_comp(index->table));
00621 
00622   if (UNIV_UNLIKELY(node_ptr)) {
00623     n_node_ptr_field = dict_index_get_n_unique_in_tree(index);
00624     n = n_node_ptr_field + 1;
00625   } else {
00626     n_node_ptr_field = ULINT_UNDEFINED;
00627     n = dict_index_get_n_fields(index);
00628   }
00629 
00630   ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
00631   rec_offs_set_n_fields(offsets, n);
00632 
00633   nulls = extra;
00634   lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
00635   i = offs = 0;
00636   null_mask = 1;
00637   any_ext = 0;
00638 
00639   /* read the lengths of fields 0..n */
00640   do {
00641     ulint len;
00642     if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
00643       len = offs += 4;
00644       goto resolved;
00645     }
00646 
00647     field = dict_index_get_nth_field(index, i);
00648     if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
00649       /* nullable field => read the null flag */
00650 
00651       if (UNIV_UNLIKELY(!(byte) null_mask)) {
00652         nulls++;
00653         null_mask = 1;
00654       }
00655 
00656       if (*nulls & null_mask) {
00657         null_mask <<= 1;
00658         /* No length is stored for NULL fields.
00659         We do not advance offs, and we set
00660         the length to zero and enable the
00661         SQL NULL flag in offsets[]. */
00662         len = offs | REC_OFFS_SQL_NULL;
00663         goto resolved;
00664       }
00665       null_mask <<= 1;
00666     }
00667 
00668     if (UNIV_UNLIKELY(!field->fixed_len)) {
00669       /* Variable-length field: read the length */
00670       const dict_col_t* col
00671         = dict_field_get_col(field);
00672       len = *lens++;
00673       /* If the maximum length of the field is up
00674       to 255 bytes, the actual length is always
00675       stored in one byte. If the maximum length is
00676       more than 255 bytes, the actual length is
00677       stored in one byte for 0..127.  The length
00678       will be encoded in two bytes when it is 128 or
00679       more, or when the field is stored externally. */
00680       if (UNIV_UNLIKELY(col->len > 255)
00681           || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
00682         if (len & 0x80) {
00683           /* 1exxxxxxx xxxxxxxx */
00684           len <<= 8;
00685           len |= *lens++;
00686 
00687           offs += len & 0x3fff;
00688           if (UNIV_UNLIKELY(len & 0x4000)) {
00689             any_ext = REC_OFFS_EXTERNAL;
00690             len = offs | REC_OFFS_EXTERNAL;
00691           } else {
00692             len = offs;
00693           }
00694 
00695           goto resolved;
00696         }
00697       }
00698 
00699       len = offs += len;
00700     } else {
00701       len = offs += field->fixed_len;
00702     }
00703 resolved:
00704     rec_offs_base(offsets)[i + 1] = len;
00705   } while (++i < rec_offs_n_fields(offsets));
00706 
00707   ut_ad(lens >= extra);
00708   *rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
00709     | REC_OFFS_COMPACT | any_ext;
00710 }
00711 
00712 /************************************************************/
00716 UNIV_INTERN
00717 ulint
00718 rec_get_nth_field_offs_old(
00719 /*=======================*/
00720   const rec_t*  rec,  
00721   ulint   n,  
00722   ulint*    len)  
00724 {
00725   ulint os;
00726   ulint next_os;
00727 
00728   ut_ad(len);
00729   ut_a(rec);
00730   ut_a(n < rec_get_n_fields_old(rec));
00731 
00732   if (rec_get_1byte_offs_flag(rec)) {
00733     os = rec_1_get_field_start_offs(rec, n);
00734 
00735     next_os = rec_1_get_field_end_info(rec, n);
00736 
00737     if (next_os & REC_1BYTE_SQL_NULL_MASK) {
00738       *len = UNIV_SQL_NULL;
00739 
00740       return(os);
00741     }
00742 
00743     next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
00744   } else {
00745     os = rec_2_get_field_start_offs(rec, n);
00746 
00747     next_os = rec_2_get_field_end_info(rec, n);
00748 
00749     if (next_os & REC_2BYTE_SQL_NULL_MASK) {
00750       *len = UNIV_SQL_NULL;
00751 
00752       return(os);
00753     }
00754 
00755     next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
00756               | REC_2BYTE_EXTERN_MASK);
00757   }
00758 
00759   *len = next_os - os;
00760 
00761   ut_ad(*len < UNIV_PAGE_SIZE);
00762 
00763   return(os);
00764 }
00765 
00766 /**********************************************************/
00769 UNIV_INTERN
00770 ulint
00771 rec_get_converted_size_comp_prefix(
00772 /*===============================*/
00773   const dict_index_t* index,  
00777   const dfield_t*   fields, 
00778   ulint     n_fields,
00779   ulint*      extra)  
00780 {
00781   ulint extra_size;
00782   ulint data_size;
00783   ulint i;
00784   ut_ad(index);
00785   ut_ad(fields);
00786   ut_ad(n_fields > 0);
00787   ut_ad(n_fields <= dict_index_get_n_fields(index));
00788 
00789   extra_size = REC_N_NEW_EXTRA_BYTES
00790     + UT_BITS_IN_BYTES(index->n_nullable);
00791   data_size = 0;
00792 
00793   /* read the lengths of fields 0..n */
00794   for (i = 0; i < n_fields; i++) {
00795     const dict_field_t* field;
00796     ulint     len;
00797     const dict_col_t* col;
00798 
00799     field = dict_index_get_nth_field(index, i);
00800     len = dfield_get_len(&fields[i]);
00801     col = dict_field_get_col(field);
00802 
00803     ut_ad(dict_col_type_assert_equal(col,
00804              dfield_get_type(&fields[i])));
00805 
00806     if (dfield_is_null(&fields[i])) {
00807       /* No length is stored for NULL fields. */
00808       ut_ad(!(col->prtype & DATA_NOT_NULL));
00809       continue;
00810     }
00811 
00812     ut_ad(len <= col->len || col->mtype == DATA_BLOB);
00813 
00814     /* If the maximum length of a variable-length field
00815     is up to 255 bytes, the actual length is always stored
00816     in one byte. If the maximum length is more than 255
00817     bytes, the actual length is stored in one byte for
00818     0..127.  The length will be encoded in two bytes when
00819     it is 128 or more, or when the field is stored externally. */
00820 
00821     if (field->fixed_len) {
00822       ut_ad(len == field->fixed_len);
00823       /* dict_index_add_col() should guarantee this */
00824       ut_ad(!field->prefix_len
00825             || field->fixed_len == field->prefix_len);
00826     } else if (dfield_is_ext(&fields[i])) {
00827       ut_ad(col->len >= 256 || col->mtype == DATA_BLOB);
00828       extra_size += 2;
00829     } else if (len < 128
00830          || (col->len < 256 && col->mtype != DATA_BLOB)) {
00831       extra_size++;
00832     } else {
00833       /* For variable-length columns, we look up the
00834       maximum length from the column itself.  If this
00835       is a prefix index column shorter than 256 bytes,
00836       this will waste one byte. */
00837       extra_size += 2;
00838     }
00839     data_size += len;
00840   }
00841 
00842   if (UNIV_LIKELY_NULL(extra)) {
00843     *extra = extra_size;
00844   }
00845 
00846   return(extra_size + data_size);
00847 }
00848 
00849 /**********************************************************/
00852 UNIV_INTERN
00853 ulint
00854 rec_get_converted_size_comp(
00855 /*========================*/
00856   const dict_index_t* index,  
00860   ulint     status, 
00861   const dfield_t*   fields, 
00862   ulint     n_fields,
00863   ulint*      extra)  
00864 {
00865   ulint size;
00866   ut_ad(index);
00867   ut_ad(fields);
00868   ut_ad(n_fields > 0);
00869 
00870   switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
00871   case REC_STATUS_ORDINARY:
00872     ut_ad(n_fields == dict_index_get_n_fields(index));
00873     size = 0;
00874     break;
00875   case REC_STATUS_NODE_PTR:
00876     n_fields--;
00877     ut_ad(n_fields == dict_index_get_n_unique_in_tree(index));
00878     ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
00879     size = REC_NODE_PTR_SIZE; /* child page number */
00880     break;
00881   case REC_STATUS_INFIMUM:
00882   case REC_STATUS_SUPREMUM:
00883     /* infimum or supremum record, 8 data bytes */
00884     if (UNIV_LIKELY_NULL(extra)) {
00885       *extra = REC_N_NEW_EXTRA_BYTES;
00886     }
00887     return(REC_N_NEW_EXTRA_BYTES + 8);
00888   default:
00889     ut_error;
00890     return(ULINT_UNDEFINED);
00891   }
00892 
00893   return(size + rec_get_converted_size_comp_prefix(index, fields,
00894                n_fields, extra));
00895 }
00896 
00897 /***********************************************************/
00899 UNIV_INTERN
00900 void
00901 rec_set_nth_field_null_bit(
00902 /*=======================*/
00903   rec_t*  rec,  
00904   ulint i,  
00905   ibool val)  
00906 {
00907   ulint info;
00908 
00909   if (rec_get_1byte_offs_flag(rec)) {
00910 
00911     info = rec_1_get_field_end_info(rec, i);
00912 
00913     if (val) {
00914       info = info | REC_1BYTE_SQL_NULL_MASK;
00915     } else {
00916       info = info & ~REC_1BYTE_SQL_NULL_MASK;
00917     }
00918 
00919     rec_1_set_field_end_info(rec, i, info);
00920 
00921     return;
00922   }
00923 
00924   info = rec_2_get_field_end_info(rec, i);
00925 
00926   if (val) {
00927     info = info | REC_2BYTE_SQL_NULL_MASK;
00928   } else {
00929     info = info & ~REC_2BYTE_SQL_NULL_MASK;
00930   }
00931 
00932   rec_2_set_field_end_info(rec, i, info);
00933 }
00934 
00935 /***********************************************************/
00938 UNIV_INTERN
00939 void
00940 rec_set_nth_field_sql_null(
00941 /*=======================*/
00942   rec_t*  rec,  
00943   ulint n)  
00944 {
00945   ulint offset;
00946 
00947   offset = rec_get_field_start_offs(rec, n);
00948 
00949   data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
00950 
00951   rec_set_nth_field_null_bit(rec, n, TRUE);
00952 }
00953 
00954 /*********************************************************/
00958 static
00959 rec_t*
00960 rec_convert_dtuple_to_rec_old(
00961 /*==========================*/
00962   byte*   buf,  
00963   const dtuple_t* dtuple, 
00964   ulint   n_ext)  
00965 {
00966   const dfield_t* field;
00967   ulint   n_fields;
00968   ulint   data_size;
00969   rec_t*    rec;
00970   ulint   end_offset;
00971   ulint   ored_offset;
00972   ulint   len;
00973   ulint   i;
00974 
00975   ut_ad(buf && dtuple);
00976   ut_ad(dtuple_validate(dtuple));
00977   ut_ad(dtuple_check_typed(dtuple));
00978 
00979   n_fields = dtuple_get_n_fields(dtuple);
00980   data_size = dtuple_get_data_size(dtuple, 0);
00981 
00982   ut_ad(n_fields > 0);
00983 
00984   /* Calculate the offset of the origin in the physical record */
00985 
00986   rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
00987 #ifdef UNIV_DEBUG
00988   /* Suppress Valgrind warnings of ut_ad()
00989   in mach_write_to_1(), mach_write_to_2() et al. */
00990   memset(buf, 0xff, rec - buf + data_size);
00991 #endif /* UNIV_DEBUG */
00992   /* Store the number of fields */
00993   rec_set_n_fields_old(rec, n_fields);
00994 
00995   /* Set the info bits of the record */
00996   rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
00997             & REC_INFO_BITS_MASK);
00998 
00999   /* Store the data and the offsets */
01000 
01001   end_offset = 0;
01002 
01003   if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) {
01004 
01005     rec_set_1byte_offs_flag(rec, TRUE);
01006 
01007     for (i = 0; i < n_fields; i++) {
01008 
01009       field = dtuple_get_nth_field(dtuple, i);
01010 
01011       if (dfield_is_null(field)) {
01012         len = dtype_get_sql_null_size(
01013           dfield_get_type(field), 0);
01014         data_write_sql_null(rec + end_offset, len);
01015 
01016         end_offset += len;
01017         ored_offset = end_offset
01018           | REC_1BYTE_SQL_NULL_MASK;
01019       } else {
01020         /* If the data is not SQL null, store it */
01021         len = dfield_get_len(field);
01022 
01023         memcpy(rec + end_offset,
01024                dfield_get_data(field), len);
01025 
01026         end_offset += len;
01027         ored_offset = end_offset;
01028       }
01029 
01030       rec_1_set_field_end_info(rec, i, ored_offset);
01031     }
01032   } else {
01033     rec_set_1byte_offs_flag(rec, FALSE);
01034 
01035     for (i = 0; i < n_fields; i++) {
01036 
01037       field = dtuple_get_nth_field(dtuple, i);
01038 
01039       if (dfield_is_null(field)) {
01040         len = dtype_get_sql_null_size(
01041           dfield_get_type(field), 0);
01042         data_write_sql_null(rec + end_offset, len);
01043 
01044         end_offset += len;
01045         ored_offset = end_offset
01046           | REC_2BYTE_SQL_NULL_MASK;
01047       } else {
01048         /* If the data is not SQL null, store it */
01049         len = dfield_get_len(field);
01050 
01051         memcpy(rec + end_offset,
01052                dfield_get_data(field), len);
01053 
01054         end_offset += len;
01055         ored_offset = end_offset;
01056 
01057         if (dfield_is_ext(field)) {
01058           ored_offset |= REC_2BYTE_EXTERN_MASK;
01059         }
01060       }
01061 
01062       rec_2_set_field_end_info(rec, i, ored_offset);
01063     }
01064   }
01065 
01066   return(rec);
01067 }
01068 
01069 /*********************************************************/
01071 UNIV_INTERN
01072 void
01073 rec_convert_dtuple_to_rec_comp(
01074 /*===========================*/
01075   rec_t*      rec,  
01076   ulint     extra,  
01080   const dict_index_t* index,  
01081   ulint     status, 
01082   const dfield_t*   fields, 
01083   ulint     n_fields)
01084 {
01085   const dfield_t* field;
01086   const dtype_t*  type;
01087   byte*   end;
01088   byte*   nulls;
01089   byte*   lens;
01090   ulint   len;
01091   ulint   i;
01092   ulint   n_node_ptr_field;
01093   ulint   fixed_len;
01094   ulint   null_mask = 1;
01095   ut_ad(extra == 0 || dict_table_is_comp(index->table));
01096   ut_ad(extra == 0 || extra == REC_N_NEW_EXTRA_BYTES);
01097   ut_ad(n_fields > 0);
01098 
01099   switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
01100   case REC_STATUS_ORDINARY:
01101     ut_ad(n_fields <= dict_index_get_n_fields(index));
01102     n_node_ptr_field = ULINT_UNDEFINED;
01103     break;
01104   case REC_STATUS_NODE_PTR:
01105     ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
01106     n_node_ptr_field = n_fields - 1;
01107     break;
01108   case REC_STATUS_INFIMUM:
01109   case REC_STATUS_SUPREMUM:
01110     ut_ad(n_fields == 1);
01111     n_node_ptr_field = ULINT_UNDEFINED;
01112     break;
01113   default:
01114     ut_error;
01115     return;
01116   }
01117 
01118   end = rec;
01119   nulls = rec - (extra + 1);
01120   lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
01121   /* clear the SQL-null flags */
01122   memset(lens + 1, 0, nulls - lens);
01123 
01124   /* Store the data and the offsets */
01125 
01126   for (i = 0, field = fields; i < n_fields; i++, field++) {
01127     const dict_field_t* ifield;
01128 
01129     type = dfield_get_type(field);
01130     len = dfield_get_len(field);
01131 
01132     if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
01133       ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
01134       ut_ad(len == 4);
01135       memcpy(end, dfield_get_data(field), len);
01136       end += 4;
01137       break;
01138     }
01139 
01140     if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
01141       /* nullable field */
01142       ut_ad(index->n_nullable > 0);
01143 
01144       if (UNIV_UNLIKELY(!(byte) null_mask)) {
01145         nulls--;
01146         null_mask = 1;
01147       }
01148 
01149       ut_ad(*nulls < null_mask);
01150 
01151       /* set the null flag if necessary */
01152       if (dfield_is_null(field)) {
01153         *nulls |= null_mask;
01154         null_mask <<= 1;
01155         continue;
01156       }
01157 
01158       null_mask <<= 1;
01159     }
01160     /* only nullable fields can be null */
01161     ut_ad(!dfield_is_null(field));
01162 
01163     ifield = dict_index_get_nth_field(index, i);
01164     fixed_len = ifield->fixed_len;
01165     /* If the maximum length of a variable-length field
01166     is up to 255 bytes, the actual length is always stored
01167     in one byte. If the maximum length is more than 255
01168     bytes, the actual length is stored in one byte for
01169     0..127.  The length will be encoded in two bytes when
01170     it is 128 or more, or when the field is stored externally. */
01171     if (fixed_len) {
01172       ut_ad(len == fixed_len);
01173       ut_ad(!dfield_is_ext(field));
01174     } else if (dfield_is_ext(field)) {
01175       ut_ad(ifield->col->len >= 256
01176             || ifield->col->mtype == DATA_BLOB);
01177       ut_ad(len <= REC_MAX_INDEX_COL_LEN
01178             + BTR_EXTERN_FIELD_REF_SIZE);
01179       *lens-- = (byte) (len >> 8) | 0xc0;
01180       *lens-- = (byte) len;
01181     } else {
01182       ut_ad(len <= dtype_get_len(type)
01183             || dtype_get_mtype(type) == DATA_BLOB);
01184       if (len < 128
01185           || (dtype_get_len(type) < 256
01186         && dtype_get_mtype(type) != DATA_BLOB)) {
01187 
01188         *lens-- = (byte) len;
01189       } else {
01190         ut_ad(len < 16384);
01191         *lens-- = (byte) (len >> 8) | 0x80;
01192         *lens-- = (byte) len;
01193       }
01194     }
01195 
01196     memcpy(end, dfield_get_data(field), len);
01197     end += len;
01198   }
01199 }
01200 
01201 /*********************************************************/
01205 static
01206 rec_t*
01207 rec_convert_dtuple_to_rec_new(
01208 /*==========================*/
01209   byte*     buf,  
01211   const dict_index_t* index,  
01212   const dtuple_t*   dtuple) 
01213 {
01214   ulint extra_size;
01215   ulint status;
01216   rec_t*  rec;
01217 
01218   status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK;
01219   rec_get_converted_size_comp(index, status,
01220             dtuple->fields, dtuple->n_fields,
01221             &extra_size);
01222   rec = buf + extra_size;
01223 
01224   rec_convert_dtuple_to_rec_comp(
01225     rec, REC_N_NEW_EXTRA_BYTES, index, status,
01226     dtuple->fields, dtuple->n_fields);
01227 
01228   /* Set the info bits of the record */
01229   rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
01230 
01231   return(rec);
01232 }
01233 
01234 /*********************************************************/
01238 UNIV_INTERN
01239 rec_t*
01240 rec_convert_dtuple_to_rec(
01241 /*======================*/
01242   byte*     buf,  
01244   const dict_index_t* index,  
01245   const dtuple_t*   dtuple, 
01246   ulint     n_ext)  
01248 {
01249   rec_t*  rec;
01250 
01251   ut_ad(buf && index && dtuple);
01252   ut_ad(dtuple_validate(dtuple));
01253   ut_ad(dtuple_check_typed(dtuple));
01254 
01255   if (dict_table_is_comp(index->table)) {
01256     rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
01257   } else {
01258     rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
01259   }
01260 
01261 #ifdef UNIV_DEBUG
01262   {
01263     mem_heap_t* heap  = NULL;
01264     ulint   offsets_[REC_OFFS_NORMAL_SIZE];
01265     const ulint*  offsets;
01266     ulint   i;
01267     rec_offs_init(offsets_);
01268 
01269     offsets = rec_get_offsets(rec, index,
01270             offsets_, ULINT_UNDEFINED, &heap);
01271     ut_ad(rec_validate(rec, offsets));
01272     ut_ad(dtuple_get_n_fields(dtuple)
01273           == rec_offs_n_fields(offsets));
01274 
01275     for (i = 0; i < rec_offs_n_fields(offsets); i++) {
01276       ut_ad(!dfield_is_ext(dtuple_get_nth_field(dtuple, i))
01277             == !rec_offs_nth_extern(offsets, i));
01278     }
01279 
01280     if (UNIV_LIKELY_NULL(heap)) {
01281       mem_heap_free(heap);
01282     }
01283   }
01284 #endif /* UNIV_DEBUG */
01285   return(rec);
01286 }
01287 
01288 /**************************************************************/
01291 UNIV_INTERN
01292 void
01293 rec_copy_prefix_to_dtuple(
01294 /*======================*/
01295   dtuple_t*   tuple,    
01296   const rec_t*    rec,    
01297   const dict_index_t* index,    
01298   ulint     n_fields, 
01300   mem_heap_t*   heap)   
01301 {
01302   ulint i;
01303   ulint offsets_[REC_OFFS_NORMAL_SIZE];
01304   ulint*  offsets = offsets_;
01305   rec_offs_init(offsets_);
01306 
01307   offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
01308 
01309   ut_ad(rec_validate(rec, offsets));
01310   ut_ad(dtuple_check_typed(tuple));
01311 
01312   dtuple_set_info_bits(tuple, rec_get_info_bits(
01313              rec, dict_table_is_comp(index->table)));
01314 
01315   for (i = 0; i < n_fields; i++) {
01316     dfield_t* field;
01317     const byte* data;
01318     ulint   len;
01319 
01320     field = dtuple_get_nth_field(tuple, i);
01321     data = rec_get_nth_field(rec, offsets, i, &len);
01322 
01323     if (len != UNIV_SQL_NULL) {
01324       dfield_set_data(field,
01325           mem_heap_dup(heap, data, len), len);
01326       ut_ad(!rec_offs_nth_extern(offsets, i));
01327     } else {
01328       dfield_set_null(field);
01329     }
01330   }
01331 }
01332 
01333 /**************************************************************/
01337 static
01338 rec_t*
01339 rec_copy_prefix_to_buf_old(
01340 /*=======================*/
01341   const rec_t*  rec,    
01342   ulint   n_fields, 
01343   ulint   area_end, 
01344   byte**    buf,    
01346   ulint*    buf_size) 
01347 {
01348   rec_t*  copy_rec;
01349   ulint area_start;
01350   ulint prefix_len;
01351 
01352   if (rec_get_1byte_offs_flag(rec)) {
01353     area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
01354   } else {
01355     area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
01356   }
01357 
01358   prefix_len = area_start + area_end;
01359 
01360   if ((*buf == NULL) || (*buf_size < prefix_len)) {
01361     if (*buf != NULL) {
01362       mem_free(*buf);
01363     }
01364 
01365     *buf = static_cast<byte *>(mem_alloc2(prefix_len, buf_size));
01366   }
01367 
01368   ut_memcpy(*buf, rec - area_start, prefix_len);
01369 
01370   copy_rec = *buf + area_start;
01371 
01372   rec_set_n_fields_old(copy_rec, n_fields);
01373 
01374   return(copy_rec);
01375 }
01376 
01377 /**************************************************************/
01381 UNIV_INTERN
01382 rec_t*
01383 rec_copy_prefix_to_buf(
01384 /*===================*/
01385   const rec_t*    rec,    
01386   const dict_index_t* index,    
01387   ulint     n_fields, 
01389   byte**      buf,    
01392   ulint*      buf_size) 
01393 {
01394   const byte* nulls;
01395   const byte* lens;
01396   ulint   i;
01397   ulint   prefix_len;
01398   ulint   null_mask;
01399   ulint   status;
01400 
01401   UNIV_PREFETCH_RW(*buf);
01402 
01403   if (!dict_table_is_comp(index->table)) {
01404     ut_ad(rec_validate_old(rec));
01405     return(rec_copy_prefix_to_buf_old(
01406              rec, n_fields,
01407              rec_get_field_start_offs(rec, n_fields),
01408              buf, buf_size));
01409   }
01410 
01411   status = rec_get_status(rec);
01412 
01413   switch (status) {
01414   case REC_STATUS_ORDINARY:
01415     ut_ad(n_fields <= dict_index_get_n_fields(index));
01416     break;
01417   case REC_STATUS_NODE_PTR:
01418     /* it doesn't make sense to copy the child page number field */
01419     ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
01420     break;
01421   case REC_STATUS_INFIMUM:
01422   case REC_STATUS_SUPREMUM:
01423     /* infimum or supremum record: no sense to copy anything */
01424   default:
01425     ut_error;
01426     return(NULL);
01427   }
01428 
01429   nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
01430   lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
01431   UNIV_PREFETCH_R(lens);
01432   prefix_len = 0;
01433   null_mask = 1;
01434 
01435   /* read the lengths of fields 0..n */
01436   for (i = 0; i < n_fields; i++) {
01437     const dict_field_t* field;
01438     const dict_col_t* col;
01439 
01440     field = dict_index_get_nth_field(index, i);
01441     col = dict_field_get_col(field);
01442 
01443     if (!(col->prtype & DATA_NOT_NULL)) {
01444       /* nullable field => read the null flag */
01445       if (UNIV_UNLIKELY(!(byte) null_mask)) {
01446         nulls--;
01447         null_mask = 1;
01448       }
01449 
01450       if (*nulls & null_mask) {
01451         null_mask <<= 1;
01452         continue;
01453       }
01454 
01455       null_mask <<= 1;
01456     }
01457 
01458     if (field->fixed_len) {
01459       prefix_len += field->fixed_len;
01460     } else {
01461       ulint len = *lens--;
01462       /* If the maximum length of the column is up
01463       to 255 bytes, the actual length is always
01464       stored in one byte. If the maximum length is
01465       more than 255 bytes, the actual length is
01466       stored in one byte for 0..127.  The length
01467       will be encoded in two bytes when it is 128 or
01468       more, or when the column is stored externally. */
01469       if (col->len > 255 || col->mtype == DATA_BLOB) {
01470         if (len & 0x80) {
01471           /* 1exxxxxx */
01472           len &= 0x3f;
01473           len <<= 8;
01474           len |= *lens--;
01475           UNIV_PREFETCH_R(lens);
01476         }
01477       }
01478       prefix_len += len;
01479     }
01480   }
01481 
01482   UNIV_PREFETCH_R(rec + prefix_len);
01483 
01484   prefix_len += rec - (lens + 1);
01485 
01486   if ((*buf == NULL) || (*buf_size < prefix_len)) {
01487     if (*buf != NULL) {
01488       mem_free(*buf);
01489     }
01490 
01491     *buf = static_cast<byte *>(mem_alloc2(prefix_len, buf_size));
01492   }
01493 
01494   memcpy(*buf, lens + 1, prefix_len);
01495 
01496   return(*buf + (rec - (lens + 1)));
01497 }
01498 
01499 /***************************************************************/
01502 static
01503 ibool
01504 rec_validate_old(
01505 /*=============*/
01506   const rec_t*  rec)  
01507 {
01508   const byte* data;
01509   ulint   len;
01510   ulint   n_fields;
01511   ulint   len_sum   = 0;
01512   ulint   sum   = 0;
01513   ulint   i;
01514 
01515   ut_a(rec);
01516   n_fields = rec_get_n_fields_old(rec);
01517 
01518   if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
01519     fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
01520       (ulong) n_fields);
01521     return(FALSE);
01522   }
01523 
01524   for (i = 0; i < n_fields; i++) {
01525     data = rec_get_nth_field_old(rec, i, &len);
01526 
01527     if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
01528       fprintf(stderr,
01529         "InnoDB: Error: record field %lu len %lu\n",
01530         (ulong) i,
01531         (ulong) len);
01532       return(FALSE);
01533     }
01534 
01535     if (len != UNIV_SQL_NULL) {
01536       len_sum += len;
01537       sum += *(data + len -1); /* dereference the
01538              end of the field to
01539              cause a memory trap
01540              if possible */
01541     } else {
01542       len_sum += rec_get_nth_field_size(rec, i);
01543     }
01544   }
01545 
01546   if (len_sum != rec_get_data_size_old(rec)) {
01547     fprintf(stderr,
01548       "InnoDB: Error: record len should be %lu, len %lu\n",
01549       (ulong) len_sum,
01550       rec_get_data_size_old(rec));
01551     return(FALSE);
01552   }
01553 
01554   rec_dummy = sum; /* This is here only to fool the compiler */
01555 
01556   return(TRUE);
01557 }
01558 
01559 /***************************************************************/
01562 UNIV_INTERN
01563 ibool
01564 rec_validate(
01565 /*=========*/
01566   const rec_t*  rec,  
01567   const ulint*  offsets)
01568 {
01569   const byte* data;
01570   ulint   len;
01571   ulint   n_fields;
01572   ulint   len_sum   = 0;
01573   ulint   sum   = 0;
01574   ulint   i;
01575 
01576   ut_a(rec);
01577   n_fields = rec_offs_n_fields(offsets);
01578 
01579   if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
01580     fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
01581       (ulong) n_fields);
01582     return(FALSE);
01583   }
01584 
01585   ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
01586 
01587   for (i = 0; i < n_fields; i++) {
01588     data = rec_get_nth_field(rec, offsets, i, &len);
01589 
01590     if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
01591       fprintf(stderr,
01592         "InnoDB: Error: record field %lu len %lu\n",
01593         (ulong) i,
01594         (ulong) len);
01595       return(FALSE);
01596     }
01597 
01598     if (len != UNIV_SQL_NULL) {
01599       len_sum += len;
01600       sum += *(data + len -1); /* dereference the
01601              end of the field to
01602              cause a memory trap
01603              if possible */
01604     } else if (!rec_offs_comp(offsets)) {
01605       len_sum += rec_get_nth_field_size(rec, i);
01606     }
01607   }
01608 
01609   if (len_sum != rec_offs_data_size(offsets)) {
01610     fprintf(stderr,
01611       "InnoDB: Error: record len should be %lu, len %lu\n",
01612       (ulong) len_sum,
01613       (ulong) rec_offs_data_size(offsets));
01614     return(FALSE);
01615   }
01616 
01617   rec_dummy = sum; /* This is here only to fool the compiler */
01618 
01619   if (!rec_offs_comp(offsets)) {
01620     ut_a(rec_validate_old(rec));
01621   }
01622 
01623   return(TRUE);
01624 }
01625 
01626 /***************************************************************/
01628 UNIV_INTERN
01629 void
01630 rec_print_old(
01631 /*==========*/
01632   FILE*   file, 
01633   const rec_t*  rec)  
01634 {
01635   const byte* data;
01636   ulint   len;
01637   ulint   n;
01638   ulint   i;
01639 
01640   ut_ad(rec);
01641 
01642   n = rec_get_n_fields_old(rec);
01643 
01644   fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
01645     " %u-byte offsets; info bits %lu\n",
01646     (ulong) n,
01647     rec_get_1byte_offs_flag(rec) ? 1 : 2,
01648     (ulong) rec_get_info_bits(rec, FALSE));
01649 
01650   for (i = 0; i < n; i++) {
01651 
01652     data = rec_get_nth_field_old(rec, i, &len);
01653 
01654     fprintf(file, " %lu:", (ulong) i);
01655 
01656     if (len != UNIV_SQL_NULL) {
01657       if (len <= 30) {
01658 
01659         ut_print_buf(file, data, len);
01660       } else {
01661         ut_print_buf(file, data, 30);
01662 
01663         fprintf(file, " (total %lu bytes)",
01664           (ulong) len);
01665       }
01666     } else {
01667       fprintf(file, " SQL NULL, size %lu ",
01668         rec_get_nth_field_size(rec, i));
01669     }
01670 
01671     putc(';', file);
01672     putc('\n', file);
01673   }
01674 
01675   rec_validate_old(rec);
01676 }
01677 
01678 #ifndef UNIV_HOTBACKUP
01679 /***************************************************************/
01682 UNIV_INTERN
01683 void
01684 rec_print_comp(
01685 /*===========*/
01686   FILE*   file, 
01687   const rec_t*  rec,  
01688   const ulint*  offsets)
01689 {
01690   ulint i;
01691 
01692   for (i = 0; i < rec_offs_n_fields(offsets); i++) {
01693     const byte* data;
01694     ulint   len;
01695 
01696     data = rec_get_nth_field(rec, offsets, i, &len);
01697 
01698     fprintf(file, " %lu:", (ulong) i);
01699 
01700     if (len != UNIV_SQL_NULL) {
01701       if (len <= 30) {
01702 
01703         ut_print_buf(file, data, len);
01704       } else {
01705         ut_print_buf(file, data, 30);
01706 
01707         fprintf(file, " (total %lu bytes)",
01708           (ulong) len);
01709       }
01710     } else {
01711       fputs(" SQL NULL", file);
01712     }
01713     putc(';', file);
01714     putc('\n', file);
01715   }
01716 }
01717 
01718 /***************************************************************/
01720 UNIV_INTERN
01721 void
01722 rec_print_new(
01723 /*==========*/
01724   FILE*   file, 
01725   const rec_t*  rec,  
01726   const ulint*  offsets)
01727 {
01728   ut_ad(rec);
01729   ut_ad(offsets);
01730   ut_ad(rec_offs_validate(rec, NULL, offsets));
01731 
01732   if (!rec_offs_comp(offsets)) {
01733     rec_print_old(file, rec);
01734     return;
01735   }
01736 
01737   fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
01738     " compact format; info bits %lu\n",
01739     (ulong) rec_offs_n_fields(offsets),
01740     (ulong) rec_get_info_bits(rec, TRUE));
01741 
01742   rec_print_comp(file, rec, offsets);
01743   rec_validate(rec, offsets);
01744 }
01745 
01746 /***************************************************************/
01748 UNIV_INTERN
01749 void
01750 rec_print(
01751 /*======*/
01752   FILE*     file, 
01753   const rec_t*    rec,  
01754   const dict_index_t* index)  
01755 {
01756   ut_ad(index);
01757 
01758   if (!dict_table_is_comp(index->table)) {
01759     rec_print_old(file, rec);
01760     return;
01761   } else {
01762     mem_heap_t* heap  = NULL;
01763     ulint   offsets_[REC_OFFS_NORMAL_SIZE];
01764     rec_offs_init(offsets_);
01765 
01766     rec_print_new(file, rec,
01767             rec_get_offsets(rec, index, offsets_,
01768                 ULINT_UNDEFINED, &heap));
01769     if (UNIV_LIKELY_NULL(heap)) {
01770       mem_heap_free(heap);
01771     }
01772   }
01773 }
01774 #endif /* !UNIV_HOTBACKUP */