Drizzled Public API Documentation

dict0load.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1996, 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 /**************************************************/
00027 #if defined(BUILD_DRIZZLE)
00028 # include "config.h"
00029 #else
00030 # include "mysql_version.h"
00031 #endif /* BUILD_DRIZZLE */
00032 #include "dict0load.h"
00033 
00034 #ifdef UNIV_NONINL
00035 #include "dict0load.ic"
00036 #endif
00037 
00038 #include "btr0pcur.h"
00039 #include "btr0btr.h"
00040 #include "page0page.h"
00041 #include "mach0data.h"
00042 #include "dict0dict.h"
00043 #include "dict0boot.h"
00044 #include "rem0cmp.h"
00045 #include "srv0start.h"
00046 #include "srv0srv.h"
00047 
00048 
00050 static const char* SYSTEM_TABLE_NAME[] = {
00051   "SYS_TABLES",
00052   "SYS_INDEXES",
00053   "SYS_COLUMNS",
00054   "SYS_FIELDS",
00055   "SYS_FOREIGN",
00056   "SYS_FOREIGN_COLS"
00057 };
00058 /****************************************************************/
00061 static
00062 ibool
00063 name_of_col_is(
00064 /*===========*/
00065   const dict_table_t* table,  
00066   const dict_index_t* index,  
00067   ulint     i,  
00068   const char*   name) 
00069 {
00070   ulint tmp = dict_col_get_no(dict_field_get_col(
00071                 dict_index_get_nth_field(
00072                   index, i)));
00073 
00074   return(strcmp(name, dict_table_get_col_name(table, tmp)) == 0);
00075 }
00076 
00077 /********************************************************************/
00081 UNIV_INTERN
00082 char*
00083 dict_get_first_table_name_in_db(
00084 /*============================*/
00085   const char* name) 
00086 {
00087   dict_table_t* sys_tables;
00088   btr_pcur_t  pcur;
00089   dict_index_t* sys_index;
00090   dtuple_t* tuple;
00091   mem_heap_t* heap;
00092   dfield_t* dfield;
00093   const rec_t*  rec;
00094   const byte* field;
00095   ulint   len;
00096   mtr_t   mtr;
00097 
00098   ut_ad(mutex_own(&(dict_sys->mutex)));
00099 
00100   heap = mem_heap_create(1000);
00101 
00102   mtr_start(&mtr);
00103 
00104   sys_tables = dict_table_get_low("SYS_TABLES");
00105   sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
00106   ut_a(!dict_table_is_comp(sys_tables));
00107 
00108   tuple = dtuple_create(heap, 1);
00109   dfield = dtuple_get_nth_field(tuple, 0);
00110 
00111   dfield_set_data(dfield, name, ut_strlen(name));
00112   dict_index_copy_types(tuple, sys_index, 1);
00113 
00114   btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
00115           BTR_SEARCH_LEAF, &pcur, &mtr);
00116 loop:
00117   rec = btr_pcur_get_rec(&pcur);
00118 
00119   if (!btr_pcur_is_on_user_rec(&pcur)) {
00120     /* Not found */
00121 
00122     btr_pcur_close(&pcur);
00123     mtr_commit(&mtr);
00124     mem_heap_free(heap);
00125 
00126     return(NULL);
00127   }
00128 
00129   field = rec_get_nth_field_old(rec, 0, &len);
00130 
00131   if (len < strlen(name)
00132       || ut_memcmp(name, field, strlen(name)) != 0) {
00133     /* Not found */
00134 
00135     btr_pcur_close(&pcur);
00136     mtr_commit(&mtr);
00137     mem_heap_free(heap);
00138 
00139     return(NULL);
00140   }
00141 
00142   if (!rec_get_deleted_flag(rec, 0)) {
00143 
00144     /* We found one */
00145 
00146     char* table_name = mem_strdupl((char*) field, len);
00147 
00148     btr_pcur_close(&pcur);
00149     mtr_commit(&mtr);
00150     mem_heap_free(heap);
00151 
00152     return(table_name);
00153   }
00154 
00155   btr_pcur_move_to_next_user_rec(&pcur, &mtr);
00156 
00157   goto loop;
00158 }
00159 
00160 /********************************************************************/
00163 UNIV_INTERN
00164 void
00165 dict_print(void)
00166 /*============*/
00167 {
00168   dict_table_t* table;
00169   btr_pcur_t  pcur;
00170   const rec_t*  rec;
00171   mem_heap_t* heap;
00172   mtr_t   mtr;
00173 
00174   /* Enlarge the fatal semaphore wait timeout during the InnoDB table
00175   monitor printout */
00176 
00177   mutex_enter(&kernel_mutex);
00178   srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
00179   mutex_exit(&kernel_mutex);
00180 
00181         heap = mem_heap_create(1000);
00182   mutex_enter(&(dict_sys->mutex));
00183 
00184   mtr_start(&mtr);
00185 
00186   rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
00187 
00188   while (rec) {
00189     const char* err_msg;
00190 
00191     err_msg = dict_process_sys_tables_rec(
00192       heap, rec, &table,
00193                         static_cast<dict_table_info>(DICT_TABLE_LOAD_FROM_CACHE
00194       | DICT_TABLE_UPDATE_STATS));
00195 
00196     mtr_commit(&mtr);
00197 
00198     if (!err_msg) {
00199       dict_table_print_low(table);
00200     } else {
00201       ut_print_timestamp(stderr);
00202       fprintf(stderr, "  InnoDB: %s\n", err_msg);
00203     }
00204 
00205     mem_heap_empty(heap);
00206 
00207     mtr_start(&mtr);
00208     rec = dict_getnext_system(&pcur, &mtr);
00209   }
00210 
00211   mtr_commit(&mtr);
00212   mutex_exit(&(dict_sys->mutex));
00213   mem_heap_free(heap);
00214 
00215   /* Restore the fatal semaphore wait timeout */
00216   mutex_enter(&kernel_mutex);
00217   srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
00218   mutex_exit(&kernel_mutex);
00219 }
00220 
00221 
00222 /********************************************************************/
00225 static
00226 const rec_t*
00227 dict_getnext_system_low(
00228 /*====================*/
00229   btr_pcur_t* pcur,   
00231   mtr_t*    mtr)    
00232 {
00233   rec_t*  rec = NULL;
00234 
00235   while (!rec || rec_get_deleted_flag(rec, 0)) {
00236     btr_pcur_move_to_next_user_rec(pcur, mtr);
00237 
00238     rec = btr_pcur_get_rec(pcur);
00239 
00240     if (!btr_pcur_is_on_user_rec(pcur)) {
00241       /* end of index */
00242       btr_pcur_close(pcur);
00243 
00244       return(NULL);
00245     }
00246   }
00247 
00248   /* Get a record, let's save the position */
00249   btr_pcur_store_position(pcur, mtr);
00250 
00251   return(rec);
00252 }
00253 
00254 /********************************************************************/
00257 UNIV_INTERN
00258 const rec_t*
00259 dict_startscan_system(
00260 /*==================*/
00261   btr_pcur_t* pcur,   
00263   mtr_t*    mtr,    
00264   dict_system_id_t system_id) 
00265 {
00266   dict_table_t* system_table;
00267   dict_index_t* clust_index;
00268   const rec_t*  rec;
00269 
00270   ut_a(system_id < SYS_NUM_SYSTEM_TABLES);
00271 
00272   system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]);
00273 
00274   clust_index = UT_LIST_GET_FIRST(system_table->indexes);
00275 
00276   btr_pcur_open_at_index_side(TRUE, clust_index, BTR_SEARCH_LEAF, pcur,
00277             TRUE, mtr);
00278 
00279   rec = dict_getnext_system_low(pcur, mtr);
00280 
00281   return(rec);
00282 }
00283 
00284 /********************************************************************/
00287 UNIV_INTERN
00288 const rec_t*
00289 dict_getnext_system(
00290 /*================*/
00291   btr_pcur_t* pcur,   
00293   mtr_t*    mtr)    
00294 {
00295         const rec_t*  rec;
00296 
00297   /* Restore the position */
00298         btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
00299 
00300   /* Get the next record */
00301         rec = dict_getnext_system_low(pcur, mtr);
00302 
00303   return(rec);
00304 }
00305 /********************************************************************/
00310 UNIV_INTERN
00311 const char*
00312 dict_process_sys_tables_rec(
00313 /*========================*/
00314   mem_heap_t* heap,   
00315   const rec_t*  rec,    
00316   dict_table_t**  table,    
00317   dict_table_info_t status) 
00321 {
00322   ulint   len;
00323   const char* field;
00324   const char* err_msg = NULL;
00325   char*   table_name;
00326 
00327   field = (const char*) rec_get_nth_field_old(rec, 0, &len);
00328 
00329   ut_a(!rec_get_deleted_flag(rec, 0));
00330 
00331   /* Get the table name */
00332   table_name = mem_heap_strdupl(heap, (const char*)field, len);
00333 
00334   /* If DICT_TABLE_LOAD_FROM_CACHE is set, first check
00335   whether there is cached dict_table_t struct first */
00336   if (status & DICT_TABLE_LOAD_FROM_CACHE) {
00337     *table = dict_table_get_low(table_name);
00338 
00339     if (!(*table)) {
00340       err_msg = "Table not found in cache";
00341     }
00342   } else {
00343     err_msg = dict_load_table_low(table_name, rec, table);
00344   }
00345 
00346   if (err_msg) {
00347     return(err_msg);
00348   }
00349 
00350   if ((status & DICT_TABLE_UPDATE_STATS)
00351       && dict_table_get_first_index(*table)) {
00352 
00353     /* Update statistics if DICT_TABLE_UPDATE_STATS
00354     is set */
00355     dict_update_statistics(*table,
00356                                        FALSE /* update even if
00357                                                 initialized */);
00358   }
00359 
00360   return(NULL);
00361 }
00362 
00363 /********************************************************************/
00368 UNIV_INTERN
00369 const char*
00370 dict_process_sys_indexes_rec(
00371 /*=========================*/
00372   mem_heap_t* heap,   
00373   const rec_t*  rec,    
00374   dict_index_t* index,    
00375   table_id_t* table_id) 
00376 {
00377   const char* err_msg;
00378   byte*   buf;
00379 
00380   buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
00381 
00382   /* Parse the record, and get "dict_index_t" struct filled */
00383   err_msg = dict_load_index_low(buf, NULL,
00384               heap, rec, FALSE, &index);
00385 
00386   *table_id = mach_read_from_8(buf);
00387 
00388   return(err_msg);
00389 }
00390 /********************************************************************/
00394 UNIV_INTERN
00395 const char*
00396 dict_process_sys_columns_rec(
00397 /*=========================*/
00398   mem_heap_t* heap,   
00399   const rec_t*  rec,    
00400   dict_col_t* column,   
00401   table_id_t* table_id, 
00402   const char**  col_name) 
00403 {
00404   const char* err_msg;
00405 
00406   /* Parse the record, and get "dict_col_t" struct filled */
00407   err_msg = dict_load_column_low(NULL, heap, column,
00408                table_id, col_name, rec);
00409 
00410   return(err_msg);
00411 }
00412 /********************************************************************/
00416 UNIV_INTERN
00417 const char*
00418 dict_process_sys_fields_rec(
00419 /*========================*/
00420   mem_heap_t* heap,   
00421   const rec_t*  rec,    
00422   dict_field_t* sys_field,  
00424   ulint*    pos,    
00425   index_id_t* index_id, 
00426   index_id_t  last_id)  
00427 {
00428   byte*   buf;
00429   byte*   last_index_id;
00430   const char* err_msg;
00431 
00432   buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
00433 
00434   last_index_id = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
00435   mach_write_to_8(last_index_id, last_id);
00436 
00437   err_msg = dict_load_field_low(buf, NULL, sys_field,
00438               pos, last_index_id, heap, rec);
00439 
00440   *index_id = mach_read_from_8(buf);
00441 
00442   return(err_msg);
00443 
00444 }
00445 /********************************************************************/
00450 UNIV_INTERN
00451 const char*
00452 dict_process_sys_foreign_rec(
00453 /*=========================*/
00454   mem_heap_t* heap,   
00455   const rec_t*  rec,    
00456   dict_foreign_t* foreign)  
00458 {
00459   ulint   len;
00460   const byte* field;
00461   ulint   n_fields_and_type;
00462 
00463   if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
00464     return("delete-marked record in SYS_FOREIGN");
00465   }
00466 
00467   if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
00468     return("wrong number of columns in SYS_FOREIGN record");
00469   }
00470 
00471   field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
00472   if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
00473 err_len:
00474     return("incorrect column length in SYS_FOREIGN");
00475   }
00476   foreign->id = mem_heap_strdupl(heap, (const char*) field, len);
00477 
00478   rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
00479   if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
00480     goto err_len;
00481   }
00482   rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
00483   if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
00484     goto err_len;
00485   }
00486 
00487   field = rec_get_nth_field_old(rec, 3/*FOR_NAME*/, &len);
00488   if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
00489     goto err_len;
00490   }
00491   foreign->foreign_table_name = mem_heap_strdupl(
00492     heap, (const char*) field, len);
00493 
00494   field = rec_get_nth_field_old(rec, 4/*REF_NAME*/, &len);
00495   if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
00496     goto err_len;
00497   }
00498   foreign->referenced_table_name = mem_heap_strdupl(
00499     heap, (const char*) field, len);
00500 
00501   field = rec_get_nth_field_old(rec, 5/*N_COLS*/, &len);
00502   if (UNIV_UNLIKELY(len != 4)) {
00503     goto err_len;
00504   }
00505   n_fields_and_type = mach_read_from_4(field);
00506 
00507   foreign->type = (unsigned int) (n_fields_and_type >> 24);
00508   foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
00509 
00510   return(NULL);
00511 }
00512 /********************************************************************/
00516 UNIV_INTERN
00517 const char*
00518 dict_process_sys_foreign_col_rec(
00519 /*=============================*/
00520   mem_heap_t* heap,   
00521   const rec_t*  rec,    
00522   const char**  name,   
00523   const char**  for_col_name, 
00524   const char**  ref_col_name, 
00526   ulint*    pos)    
00527 {
00528   ulint   len;
00529   const byte* field;
00530 
00531   if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
00532     return("delete-marked record in SYS_FOREIGN_COLS");
00533   }
00534 
00535   if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
00536     return("wrong number of columns in SYS_FOREIGN_COLS record");
00537   }
00538 
00539   field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
00540   if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
00541 err_len:
00542     return("incorrect column length in SYS_FOREIGN_COLS");
00543   }
00544   *name = mem_heap_strdupl(heap, (char*) field, len);
00545 
00546   field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
00547   if (UNIV_UNLIKELY(len != 4)) {
00548     goto err_len;
00549   }
00550   *pos = mach_read_from_4(field);
00551 
00552   rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
00553   if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
00554     goto err_len;
00555   }
00556   rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
00557   if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
00558     goto err_len;
00559   }
00560 
00561   field = rec_get_nth_field_old(rec, 4/*FOR_COL_NAME*/, &len);
00562   if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
00563     goto err_len;
00564   }
00565   *for_col_name = mem_heap_strdupl(heap, (char*) field, len);
00566 
00567   field = rec_get_nth_field_old(rec, 5/*REF_COL_NAME*/, &len);
00568   if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
00569     goto err_len;
00570   }
00571   *ref_col_name = mem_heap_strdupl(heap, (char*) field, len);
00572 
00573   return(NULL);
00574 }
00575 
00576 /*
00577   Send data to callback function .
00578 */
00579 
00580 UNIV_INTERN void dict_print_with_callback(dict_print_callback func, void *func_arg)
00581 {
00582   dict_table_t* sys_tables;
00583   dict_index_t* sys_index;
00584   btr_pcur_t  pcur;
00585   const rec_t*  rec;
00586   const byte* field;
00587   ulint   len;
00588   mtr_t   mtr;
00589 
00590   /* Enlarge the fatal semaphore wait timeout during the InnoDB table
00591   monitor printout */
00592 
00593   mutex_enter(&kernel_mutex);
00594   srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
00595   mutex_exit(&kernel_mutex);
00596 
00597   mutex_enter(&(dict_sys->mutex));
00598 
00599   mtr_start(&mtr);
00600 
00601   sys_tables = dict_table_get_low("SYS_TABLES");
00602   sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
00603 
00604   btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
00605             TRUE, &mtr);
00606 loop:
00607   btr_pcur_move_to_next_user_rec(&pcur, &mtr);
00608 
00609   rec = btr_pcur_get_rec(&pcur);
00610 
00611   if (!btr_pcur_is_on_user_rec(&pcur)) {
00612     /* end of index */
00613 
00614     btr_pcur_close(&pcur);
00615     mtr_commit(&mtr);
00616 
00617     mutex_exit(&(dict_sys->mutex));
00618 
00619     /* Restore the fatal semaphore wait timeout */
00620 
00621     mutex_enter(&kernel_mutex);
00622     srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
00623     mutex_exit(&kernel_mutex);
00624 
00625     return;
00626   }
00627 
00628   field = rec_get_nth_field_old(rec, 0, &len);
00629 
00630   if (!rec_get_deleted_flag(rec, 0)) {
00631 
00632     /* We found one */
00633 
00634     char* table_name = mem_strdupl((char*) field, len);
00635 
00636     btr_pcur_store_position(&pcur, &mtr);
00637 
00638     mtr_commit(&mtr);
00639 
00640                 func(func_arg, table_name);
00641     mem_free(table_name);
00642 
00643     mtr_start(&mtr);
00644 
00645     btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
00646   }
00647 
00648   goto loop;
00649 }
00650 
00651 /********************************************************************/
00655 static
00656 ulint
00657 dict_sys_tables_get_flags(
00658 /*======================*/
00659   const rec_t*  rec)  
00660 {
00661   const byte* field;
00662   ulint   len;
00663   ulint   n_cols;
00664   ulint   flags;
00665 
00666   field = rec_get_nth_field_old(rec, 5, &len);
00667   ut_a(len == 4);
00668 
00669   flags = mach_read_from_4(field);
00670 
00671   if (UNIV_LIKELY(flags == DICT_TABLE_ORDINARY)) {
00672     return(0);
00673   }
00674 
00675   field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
00676   n_cols = mach_read_from_4(field);
00677 
00678   if (UNIV_UNLIKELY(!(n_cols & 0x80000000UL))) {
00679     /* New file formats require ROW_FORMAT=COMPACT. */
00680     return(ULINT_UNDEFINED);
00681   }
00682 
00683   switch (flags & (DICT_TF_FORMAT_MASK | DICT_TF_COMPACT)) {
00684   default:
00685   case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
00686   case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT | DICT_TF_COMPACT:
00687     /* flags should be DICT_TABLE_ORDINARY,
00688     or DICT_TF_FORMAT_MASK should be nonzero. */
00689     return(ULINT_UNDEFINED);
00690 
00691   case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT | DICT_TF_COMPACT:
00692 #if DICT_TF_FORMAT_MAX > DICT_TF_FORMAT_ZIP
00693 # error "missing case labels for DICT_TF_FORMAT_ZIP .. DICT_TF_FORMAT_MAX"
00694 #endif
00695     /* We support this format. */
00696     break;
00697   }
00698 
00699   if (UNIV_UNLIKELY((flags & DICT_TF_ZSSIZE_MASK)
00700         > (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT))) {
00701     /* Unsupported compressed page size. */
00702     return(ULINT_UNDEFINED);
00703   }
00704 
00705   if (UNIV_UNLIKELY(flags & (SIZE_MAX << DICT_TF_BITS))) {
00706     /* Some unused bits are set. */
00707     return(ULINT_UNDEFINED);
00708   }
00709 
00710   return(flags);
00711 }
00712 
00713 /********************************************************************/
00721 UNIV_INTERN
00722 void
00723 dict_check_tablespaces_and_store_max_id(
00724 /*====================================*/
00725   ibool in_crash_recovery)  
00726 {
00727   dict_table_t* sys_tables;
00728   dict_index_t* sys_index;
00729   btr_pcur_t  pcur;
00730   const rec_t*  rec;
00731   ulint   max_space_id;
00732   mtr_t   mtr;
00733 
00734   mutex_enter(&(dict_sys->mutex));
00735 
00736   mtr_start(&mtr);
00737 
00738   sys_tables = dict_table_get_low("SYS_TABLES");
00739   sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
00740   ut_a(!dict_table_is_comp(sys_tables));
00741 
00742   max_space_id = mtr_read_ulint(dict_hdr_get(&mtr)
00743               + DICT_HDR_MAX_SPACE_ID,
00744               MLOG_4BYTES, &mtr);
00745   fil_set_max_space_id_if_bigger(max_space_id);
00746 
00747   btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
00748             TRUE, &mtr);
00749 loop:
00750   btr_pcur_move_to_next_user_rec(&pcur, &mtr);
00751 
00752   rec = btr_pcur_get_rec(&pcur);
00753 
00754   if (!btr_pcur_is_on_user_rec(&pcur)) {
00755     /* end of index */
00756 
00757     btr_pcur_close(&pcur);
00758     mtr_commit(&mtr);
00759 
00760     /* We must make the tablespace cache aware of the biggest
00761     known space id */
00762 
00763     /* printf("Biggest space id in data dictionary %lu\n",
00764     max_space_id); */
00765     fil_set_max_space_id_if_bigger(max_space_id);
00766 
00767     mutex_exit(&(dict_sys->mutex));
00768 
00769     return;
00770   }
00771 
00772   if (!rec_get_deleted_flag(rec, 0)) {
00773 
00774     /* We found one */
00775     const byte* field;
00776     ulint   len;
00777     ulint   space_id;
00778     ulint   flags;
00779     char*   name;
00780 
00781     field = rec_get_nth_field_old(rec, 0, &len);
00782     name = mem_strdupl((char*) field, len);
00783 
00784     flags = dict_sys_tables_get_flags(rec);
00785     if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
00786 
00787       field = rec_get_nth_field_old(rec, 5, &len);
00788       flags = mach_read_from_4(field);
00789 
00790       ut_print_timestamp(stderr);
00791       fputs("  InnoDB: Error: table ", stderr);
00792       ut_print_filename(stderr, name);
00793       fprintf(stderr, "\n"
00794         "InnoDB: in InnoDB data dictionary"
00795         " has unknown type %lx.\n",
00796         (ulong) flags);
00797 
00798       goto loop;
00799     }
00800 
00801     field = rec_get_nth_field_old(rec, 9, &len);
00802     ut_a(len == 4);
00803 
00804     space_id = mach_read_from_4(field);
00805 
00806     btr_pcur_store_position(&pcur, &mtr);
00807 
00808     mtr_commit(&mtr);
00809 
00810     if (space_id == 0) {
00811       /* The system tablespace always exists. */
00812     } else if (in_crash_recovery) {
00813       /* Check that the tablespace (the .ibd file) really
00814       exists; print a warning to the .err log if not.
00815       Do not print warnings for temporary tables. */
00816       ibool is_temp;
00817 
00818       field = rec_get_nth_field_old(rec, 4, &len);
00819       if (0x80000000UL &  mach_read_from_4(field)) {
00820         /* ROW_FORMAT=COMPACT: read the is_temp
00821         flag from SYS_TABLES.MIX_LEN. */
00822         field = rec_get_nth_field_old(rec, 7, &len);
00823         is_temp = mach_read_from_4(field)
00824           & DICT_TF2_TEMPORARY;
00825       } else {
00826         /* For tables created with old versions
00827         of InnoDB, SYS_TABLES.MIX_LEN may contain
00828         garbage.  Such tables would always be
00829         in ROW_FORMAT=REDUNDANT.  Pretend that
00830         all such tables are non-temporary.  That is,
00831         do not suppress error printouts about
00832         temporary tables not being found. */
00833         is_temp = FALSE;
00834       }
00835 
00836       fil_space_for_table_exists_in_mem(
00837         space_id, name, is_temp, TRUE, !is_temp);
00838     } else {
00839       /* It is a normal database startup: create the space
00840       object and check that the .ibd file exists. */
00841 
00842       fil_open_single_table_tablespace(FALSE, space_id,
00843                flags, name);
00844     }
00845 
00846     mem_free(name);
00847 
00848     if (space_id > max_space_id) {
00849       max_space_id = space_id;
00850     }
00851 
00852     mtr_start(&mtr);
00853 
00854     btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
00855   }
00856 
00857   goto loop;
00858 }
00859 
00860 /********************************************************************/
00864 UNIV_INTERN
00865 const char*
00866 dict_load_column_low(
00867 /*=================*/
00868   dict_table_t* table,    
00872   mem_heap_t* heap,   
00874   dict_col_t* column,   
00876   table_id_t* table_id, 
00877   const char**  col_name, 
00878   const rec_t*  rec)    
00879 {
00880   char*   name;
00881   const byte* field;
00882   ulint   len;
00883   ulint   mtype;
00884   ulint   prtype;
00885   ulint   col_len;
00886   ulint   pos = 0;
00887 
00888   ut_ad(table || column);
00889 
00890   if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
00891     return("delete-marked record in SYS_COLUMNS");
00892   }
00893 
00894   if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
00895     return("wrong number of columns in SYS_COLUMNS record");
00896   }
00897 
00898   field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
00899   if (UNIV_UNLIKELY(len != 8)) {
00900 err_len:
00901     return("incorrect column length in SYS_COLUMNS");
00902   }
00903 
00904   if (table_id) {
00905     *table_id = mach_read_from_8(field);
00906   } else if (UNIV_UNLIKELY(table->id != mach_read_from_8(field))) {
00907     return("SYS_COLUMNS.TABLE_ID mismatch");
00908   }
00909 
00910   field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
00911   if (UNIV_UNLIKELY(len != 4)) {
00912 
00913     goto err_len;
00914   }
00915 
00916   pos = mach_read_from_4(field);
00917 
00918   if (UNIV_UNLIKELY(table && table->n_def != pos)) {
00919     return("SYS_COLUMNS.POS mismatch");
00920   }
00921 
00922   rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
00923   if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
00924     goto err_len;
00925   }
00926   rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
00927   if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
00928     goto err_len;
00929   }
00930 
00931   field = rec_get_nth_field_old(rec, 4/*NAME*/, &len);
00932   if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
00933     goto err_len;
00934   }
00935 
00936   name = mem_heap_strdupl(heap, (const char*) field, len);
00937 
00938   if (col_name) {
00939     *col_name = name;
00940   }
00941 
00942   field = rec_get_nth_field_old(rec, 5/*MTYPE*/, &len);
00943   if (UNIV_UNLIKELY(len != 4)) {
00944     goto err_len;
00945   }
00946 
00947   mtype = mach_read_from_4(field);
00948 
00949   field = rec_get_nth_field_old(rec, 6/*PRTYPE*/, &len);
00950   if (UNIV_UNLIKELY(len != 4)) {
00951     goto err_len;
00952   }
00953   prtype = mach_read_from_4(field);
00954 
00955   if (dtype_get_charset_coll(prtype) == 0
00956       && dtype_is_string_type(mtype)) {
00957     /* The table was created with < 4.1.2. */
00958 
00959     if (dtype_is_binary_string_type(mtype, prtype)) {
00960       /* Use the binary collation for
00961       string columns of binary type. */
00962 
00963       prtype = dtype_form_prtype(
00964         prtype,
00965         DATA_MYSQL_BINARY_CHARSET_COLL);
00966     } else {
00967       /* Use the default charset for
00968       other than binary columns. */
00969 
00970       prtype = dtype_form_prtype(
00971         prtype,
00972         data_mysql_default_charset_coll);
00973     }
00974   }
00975 
00976   field = rec_get_nth_field_old(rec, 7/*LEN*/, &len);
00977   if (UNIV_UNLIKELY(len != 4)) {
00978     goto err_len;
00979   }
00980   col_len = mach_read_from_4(field);
00981   field = rec_get_nth_field_old(rec, 8/*PREC*/, &len);
00982   if (UNIV_UNLIKELY(len != 4)) {
00983     goto err_len;
00984   }
00985 
00986   if (!column) {
00987     dict_mem_table_add_col(table, heap, name, mtype,
00988                prtype, col_len);
00989   } else {
00990     dict_mem_fill_column_struct(column, pos, mtype,
00991               prtype, col_len);
00992   }
00993 
00994   return(NULL);
00995 }
00996 
00997 /********************************************************************/
00999 static
01000 void
01001 dict_load_columns(
01002 /*==============*/
01003   dict_table_t* table,  
01004   mem_heap_t* heap) 
01006 {
01007   dict_table_t* sys_columns;
01008   dict_index_t* sys_index;
01009   btr_pcur_t  pcur;
01010   dtuple_t* tuple;
01011   dfield_t* dfield;
01012   const rec_t*  rec;
01013   byte*   buf;
01014   ulint   i;
01015   mtr_t   mtr;
01016 
01017   ut_ad(mutex_own(&(dict_sys->mutex)));
01018 
01019   mtr_start(&mtr);
01020 
01021   sys_columns = dict_table_get_low("SYS_COLUMNS");
01022   sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
01023   ut_a(!dict_table_is_comp(sys_columns));
01024 
01025   ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
01026   ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
01027 
01028   tuple = dtuple_create(heap, 1);
01029   dfield = dtuple_get_nth_field(tuple, 0);
01030 
01031   buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
01032   mach_write_to_8(buf, table->id);
01033 
01034   dfield_set_data(dfield, buf, 8);
01035   dict_index_copy_types(tuple, sys_index, 1);
01036 
01037   btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
01038           BTR_SEARCH_LEAF, &pcur, &mtr);
01039   for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
01040     const char* err_msg;
01041 
01042     rec = btr_pcur_get_rec(&pcur);
01043 
01044     ut_a(btr_pcur_is_on_user_rec(&pcur));
01045 
01046     err_msg = dict_load_column_low(table, heap, NULL, NULL,
01047                  NULL, rec);
01048 
01049     if (err_msg) {
01050       fprintf(stderr, "InnoDB: %s\n", err_msg);
01051       ut_error;
01052     }
01053 
01054     btr_pcur_move_to_next_user_rec(&pcur, &mtr);
01055   }
01056 
01057   btr_pcur_close(&pcur);
01058   mtr_commit(&mtr);
01059 }
01060 
01062 static const char* dict_load_field_del = "delete-marked record in SYS_FIELDS";
01063 
01064 /********************************************************************/
01068 UNIV_INTERN
01069 const char*
01070 dict_load_field_low(
01071 /*================*/
01072   byte*   index_id, 
01075   dict_index_t* index,    
01079   dict_field_t* sys_field,  
01081   ulint*    pos,    
01082   byte*   last_index_id,  
01083   mem_heap_t* heap,   
01085   const rec_t*  rec)    
01086 {
01087   const byte* field;
01088   ulint   len;
01089   ulint   pos_and_prefix_len;
01090   ulint   prefix_len;
01091   ibool   first_field;
01092   ulint   position;
01093 
01094   /* Either index or sys_field is supplied, not both */
01095   ut_a((!index) || (!sys_field));
01096 
01097   if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
01098     return(dict_load_field_del);
01099   }
01100 
01101   if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
01102     return("wrong number of columns in SYS_FIELDS record");
01103   }
01104 
01105   field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
01106   if (UNIV_UNLIKELY(len != 8)) {
01107 err_len:
01108     return("incorrect column length in SYS_FIELDS");
01109   }
01110 
01111   if (!index) {
01112     ut_a(last_index_id);
01113     memcpy(index_id, (const char*)field, 8);
01114     first_field = memcmp(index_id, last_index_id, 8);
01115   } else {
01116     first_field = (index->n_def == 0);
01117     if (memcmp(field, index_id, 8)) {
01118       return("SYS_FIELDS.INDEX_ID mismatch");
01119     }
01120   }
01121 
01122   field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
01123   if (UNIV_UNLIKELY(len != 4)) {
01124     goto err_len;
01125   }
01126 
01127   rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
01128   if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
01129     goto err_len;
01130   }
01131   rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
01132   if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
01133     goto err_len;
01134   }
01135 
01136   /* The next field stores the field position in the index and a
01137   possible column prefix length if the index field does not
01138   contain the whole column. The storage format is like this: if
01139   there is at least one prefix field in the index, then the HIGH
01140   2 bytes contain the field number (index->n_def) and the low 2
01141   bytes the prefix length for the field. Otherwise the field
01142   number (index->n_def) is contained in the 2 LOW bytes. */
01143 
01144   pos_and_prefix_len = mach_read_from_4(field);
01145 
01146   if (index && UNIV_UNLIKELY
01147       ((pos_and_prefix_len & 0xFFFFUL) != index->n_def
01148        && (pos_and_prefix_len >> 16 & 0xFFFF) != index->n_def)) {
01149     return("SYS_FIELDS.POS mismatch");
01150   }
01151 
01152   if (first_field || pos_and_prefix_len > 0xFFFFUL) {
01153     prefix_len = pos_and_prefix_len & 0xFFFFUL;
01154     position = (pos_and_prefix_len & 0xFFFF0000UL)  >> 16;
01155   } else {
01156     prefix_len = 0;
01157     position = pos_and_prefix_len & 0xFFFFUL;
01158   }
01159 
01160   field = rec_get_nth_field_old(rec, 4, &len);
01161   if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
01162     goto err_len;
01163   }
01164 
01165   if (index) {
01166     dict_mem_index_add_field(
01167       index, mem_heap_strdupl(heap, (const char*) field, len),
01168       prefix_len);
01169   } else {
01170     ut_a(sys_field);
01171     ut_a(pos);
01172 
01173     sys_field->name = mem_heap_strdupl(
01174       heap, (const char*) field, len);
01175     sys_field->prefix_len = prefix_len;
01176     *pos = position;
01177   }
01178 
01179   return(NULL);
01180 }
01181 
01182 /********************************************************************/
01185 static
01186 ulint
01187 dict_load_fields(
01188 /*=============*/
01189   dict_index_t* index,  
01190   mem_heap_t* heap) 
01191 {
01192   dict_table_t* sys_fields;
01193   dict_index_t* sys_index;
01194   btr_pcur_t  pcur;
01195   dtuple_t* tuple;
01196   dfield_t* dfield;
01197   const rec_t*  rec;
01198   byte*   buf;
01199   ulint   i;
01200   mtr_t   mtr;
01201   ulint   error;
01202 
01203   ut_ad(mutex_own(&(dict_sys->mutex)));
01204 
01205   mtr_start(&mtr);
01206 
01207   sys_fields = dict_table_get_low("SYS_FIELDS");
01208   sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
01209   ut_a(!dict_table_is_comp(sys_fields));
01210   ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
01211 
01212   tuple = dtuple_create(heap, 1);
01213   dfield = dtuple_get_nth_field(tuple, 0);
01214 
01215   buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
01216   mach_write_to_8(buf, index->id);
01217 
01218   dfield_set_data(dfield, buf, 8);
01219   dict_index_copy_types(tuple, sys_index, 1);
01220 
01221   btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
01222           BTR_SEARCH_LEAF, &pcur, &mtr);
01223   for (i = 0; i < index->n_fields; i++) {
01224     const char* err_msg;
01225 
01226     rec = btr_pcur_get_rec(&pcur);
01227 
01228     ut_a(btr_pcur_is_on_user_rec(&pcur));
01229 
01230     err_msg = dict_load_field_low(buf, index, NULL, NULL, NULL,
01231                 heap, rec);
01232 
01233     if (err_msg == dict_load_field_del) {
01234       /* There could be delete marked records in
01235       SYS_FIELDS because SYS_FIELDS.INDEX_ID can be
01236       updated by ALTER TABLE ADD INDEX. */
01237 
01238       goto next_rec;
01239     } else if (err_msg) {
01240       fprintf(stderr, "InnoDB: %s\n", err_msg);
01241       error = DB_CORRUPTION;
01242       goto func_exit;
01243     }
01244 next_rec:
01245     btr_pcur_move_to_next_user_rec(&pcur, &mtr);
01246   }
01247 
01248   error = DB_SUCCESS;
01249 func_exit:
01250   btr_pcur_close(&pcur);
01251   mtr_commit(&mtr);
01252   return(error);
01253 }
01254 
01256 static const char* dict_load_index_del = "delete-marked record in SYS_INDEXES";
01258 static const char* dict_load_index_id_err = "SYS_INDEXES.TABLE_ID mismatch";
01259 
01260 /********************************************************************/
01266 UNIV_INTERN
01267 const char*
01268 dict_load_index_low(
01269 /*================*/
01270   byte*   table_id, 
01273   const char* table_name, 
01274   mem_heap_t* heap,   
01275   const rec_t*  rec,    
01276   ibool   allocate, 
01279   dict_index_t**  index)    
01280 {
01281   const byte* field;
01282   ulint   len;
01283   ulint   name_len;
01284   char*   name_buf;
01285   index_id_t  id;
01286   ulint   n_fields;
01287   ulint   type;
01288   ulint   space;
01289 
01290   if (allocate) {
01291     /* If allocate=TRUE, no dict_index_t will
01292     be supplied. Initialize "*index" to NULL */
01293     *index = NULL;
01294   }
01295 
01296   if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
01297     return(dict_load_index_del);
01298   }
01299 
01300   if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
01301     return("wrong number of columns in SYS_INDEXES record");
01302   }
01303 
01304   field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
01305   if (UNIV_UNLIKELY(len != 8)) {
01306 err_len:
01307     return("incorrect column length in SYS_INDEXES");
01308   }
01309 
01310   if (!allocate) {
01311     /* We are reading a SYS_INDEXES record. Copy the table_id */
01312     memcpy(table_id, (const char*)field, 8);
01313   } else if (memcmp(field, table_id, 8)) {
01314     /* Caller supplied table_id, verify it is the same
01315     id as on the index record */
01316     return(dict_load_index_id_err);
01317   }
01318 
01319   field = rec_get_nth_field_old(rec, 1/*ID*/, &len);
01320   if (UNIV_UNLIKELY(len != 8)) {
01321     goto err_len;
01322   }
01323 
01324   id = mach_read_from_8(field);
01325 
01326   rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
01327   if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
01328     goto err_len;
01329   }
01330   rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
01331   if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
01332     goto err_len;
01333   }
01334 
01335   field = rec_get_nth_field_old(rec, 4/*NAME*/, &name_len);
01336   if (UNIV_UNLIKELY(name_len == UNIV_SQL_NULL)) {
01337     goto err_len;
01338   }
01339 
01340   name_buf = mem_heap_strdupl(heap, (const char*) field,
01341             name_len);
01342 
01343   field = rec_get_nth_field_old(rec, 5/*N_FIELDS*/, &len);
01344   if (UNIV_UNLIKELY(len != 4)) {
01345     goto err_len;
01346   }
01347   n_fields = mach_read_from_4(field);
01348 
01349   field = rec_get_nth_field_old(rec, 6/*TYPE*/, &len);
01350   if (UNIV_UNLIKELY(len != 4)) {
01351     goto err_len;
01352   }
01353   type = mach_read_from_4(field);
01354 
01355   field = rec_get_nth_field_old(rec, 7/*SPACE*/, &len);
01356   if (UNIV_UNLIKELY(len != 4)) {
01357     goto err_len;
01358   }
01359   space = mach_read_from_4(field);
01360 
01361   field = rec_get_nth_field_old(rec, 8/*PAGE_NO*/, &len);
01362   if (UNIV_UNLIKELY(len != 4)) {
01363     goto err_len;
01364   }
01365 
01366   if (allocate) {
01367     *index = dict_mem_index_create(table_name, name_buf,
01368                  space, type, n_fields);
01369   } else {
01370     ut_a(*index);
01371 
01372     dict_mem_fill_index_struct(*index, NULL, NULL, name_buf,
01373              space, type, n_fields);
01374   }
01375 
01376   (*index)->id = id;
01377   (*index)->page = mach_read_from_4(field);
01378   ut_ad((*index)->page);
01379 
01380   return(NULL);
01381 }
01382 
01383 /********************************************************************/
01388 static
01389 ulint
01390 dict_load_indexes(
01391 /*==============*/
01392   dict_table_t* table,  
01393   mem_heap_t* heap) 
01394 {
01395   dict_table_t* sys_indexes;
01396   dict_index_t* sys_index;
01397   btr_pcur_t  pcur;
01398   dtuple_t* tuple;
01399   dfield_t* dfield;
01400   const rec_t*  rec;
01401   byte*   buf;
01402   mtr_t   mtr;
01403   ulint   error = DB_SUCCESS;
01404 
01405   ut_ad(mutex_own(&(dict_sys->mutex)));
01406 
01407   mtr_start(&mtr);
01408 
01409   sys_indexes = dict_table_get_low("SYS_INDEXES");
01410   sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
01411   ut_a(!dict_table_is_comp(sys_indexes));
01412   ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
01413   ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
01414 
01415   tuple = dtuple_create(heap, 1);
01416   dfield = dtuple_get_nth_field(tuple, 0);
01417 
01418   buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
01419   mach_write_to_8(buf, table->id);
01420 
01421   dfield_set_data(dfield, buf, 8);
01422   dict_index_copy_types(tuple, sys_index, 1);
01423 
01424   btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
01425           BTR_SEARCH_LEAF, &pcur, &mtr);
01426   for (;;) {
01427     dict_index_t* index = NULL;
01428     const char* err_msg;
01429 
01430     if (!btr_pcur_is_on_user_rec(&pcur)) {
01431 
01432       break;
01433     }
01434 
01435     rec = btr_pcur_get_rec(&pcur);
01436 
01437     err_msg = dict_load_index_low(buf, table->name, heap, rec,
01438                 TRUE, &index);
01439     ut_ad((index == NULL) == (err_msg != NULL));
01440 
01441     if (err_msg == dict_load_index_id_err) {
01442       /* TABLE_ID mismatch means that we have
01443       run out of index definitions for the table. */
01444       break;
01445     } else if (err_msg == dict_load_index_del) {
01446       /* Skip delete-marked records. */
01447       goto next_rec;
01448     } else if (err_msg) {
01449       fprintf(stderr, "InnoDB: %s\n", err_msg);
01450       error = DB_CORRUPTION;
01451       goto func_exit;
01452     }
01453 
01454     ut_ad(index);
01455 
01456     /* We check for unsupported types first, so that the
01457     subsequent checks are relevant for the supported types. */
01458     if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
01459 
01460       fprintf(stderr,
01461         "InnoDB: Error: unknown type %lu"
01462         " of index %s of table %s\n",
01463         (ulong) index->type, index->name, table->name);
01464 
01465       error = DB_UNSUPPORTED;
01466       dict_mem_index_free(index);
01467       goto func_exit;
01468     } else if (index->page == FIL_NULL) {
01469 
01470       fprintf(stderr,
01471         "InnoDB: Error: trying to load index %s"
01472         " for table %s\n"
01473         "InnoDB: but the index tree has been freed!\n",
01474         index->name, table->name);
01475 
01476 corrupted:
01477       dict_mem_index_free(index);
01478       error = DB_CORRUPTION;
01479       goto func_exit;
01480     } else if (!dict_index_is_clust(index)
01481          && NULL == dict_table_get_first_index(table)) {
01482 
01483       fputs("InnoDB: Error: trying to load index ",
01484             stderr);
01485       ut_print_name(stderr, NULL, FALSE, index->name);
01486       fputs(" for table ", stderr);
01487       ut_print_name(stderr, NULL, TRUE, table->name);
01488       fputs("\nInnoDB: but the first index"
01489             " is not clustered!\n", stderr);
01490 
01491       goto corrupted;
01492     } else if (table->id < DICT_HDR_FIRST_ID
01493          && (dict_index_is_clust(index)
01494              || ((table == dict_sys->sys_tables)
01495            && !strcmp("ID_IND", index->name)))) {
01496 
01497       /* The index was created in memory already at booting
01498       of the database server */
01499       dict_mem_index_free(index);
01500     } else {
01501       dict_load_fields(index, heap);
01502       error = dict_index_add_to_cache(table, index,
01503               index->page, FALSE);
01504       /* The data dictionary tables should never contain
01505       invalid index definitions.  If we ignored this error
01506       and simply did not load this index definition, the
01507       .frm file would disagree with the index definitions
01508       inside InnoDB. */
01509       if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
01510 
01511         goto func_exit;
01512       }
01513     }
01514 
01515 next_rec:
01516     btr_pcur_move_to_next_user_rec(&pcur, &mtr);
01517   }
01518 
01519 func_exit:
01520   btr_pcur_close(&pcur);
01521   mtr_commit(&mtr);
01522 
01523   return(error);
01524 }
01525 
01526 /********************************************************************/
01530 UNIV_INTERN
01531 const char*
01532 dict_load_table_low(
01533 /*================*/
01534   const char* name,   
01535   const rec_t*  rec,    
01536   dict_table_t**  table)    
01537 {
01538   const byte* field;
01539   ulint   len;
01540   ulint   space;
01541   ulint   n_cols;
01542   ulint   flags;
01543 
01544   if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
01545     return("delete-marked record in SYS_TABLES");
01546   }
01547 
01548   if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 10)) {
01549     return("wrong number of columns in SYS_TABLES record");
01550   }
01551 
01552   rec_get_nth_field_offs_old(rec, 0/*NAME*/, &len);
01553   if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
01554 err_len:
01555     return("incorrect column length in SYS_TABLES");
01556   }
01557   rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
01558   if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
01559     goto err_len;
01560   }
01561   rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
01562   if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
01563     goto err_len;
01564   }
01565 
01566   rec_get_nth_field_offs_old(rec, 3/*ID*/, &len);
01567   if (UNIV_UNLIKELY(len != 8)) {
01568     goto err_len;
01569   }
01570 
01571   field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
01572   if (UNIV_UNLIKELY(len != 4)) {
01573     goto err_len;
01574   }
01575 
01576   n_cols = mach_read_from_4(field);
01577 
01578   rec_get_nth_field_offs_old(rec, 5/*TYPE*/, &len);
01579   if (UNIV_UNLIKELY(len != 4)) {
01580     goto err_len;
01581   }
01582 
01583   rec_get_nth_field_offs_old(rec, 6/*MIX_ID*/, &len);
01584   if (UNIV_UNLIKELY(len != 8)) {
01585     goto err_len;
01586   }
01587 
01588   rec_get_nth_field_offs_old(rec, 7/*MIX_LEN*/, &len);
01589   if (UNIV_UNLIKELY(len != 4)) {
01590     goto err_len;
01591   }
01592 
01593   rec_get_nth_field_offs_old(rec, 8/*CLUSTER_ID*/, &len);
01594   if (UNIV_UNLIKELY(len != UNIV_SQL_NULL)) {
01595     goto err_len;
01596   }
01597 
01598   field = rec_get_nth_field_old(rec, 9/*SPACE*/, &len);
01599 
01600   if (UNIV_UNLIKELY(len != 4)) {
01601     goto err_len;
01602   }
01603 
01604   space = mach_read_from_4(field);
01605 
01606   /* Check if the tablespace exists and has the right name */
01607   if (space != 0) {
01608     flags = dict_sys_tables_get_flags(rec);
01609 
01610     if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
01611       field = rec_get_nth_field_old(rec, 5/*TYPE*/, &len);
01612       ut_ad(len == 4); /* this was checked earlier */
01613       flags = mach_read_from_4(field);
01614 
01615       ut_print_timestamp(stderr);
01616       fputs("  InnoDB: Error: table ", stderr);
01617       ut_print_filename(stderr, name);
01618       fprintf(stderr, "\n"
01619         "InnoDB: in InnoDB data dictionary"
01620         " has unknown type %lx.\n",
01621         (ulong) flags);
01622       return(NULL);
01623     }
01624   } else {
01625     flags = 0;
01626   }
01627 
01628   /* The high-order bit of N_COLS is the "compact format" flag.
01629   For tables in that format, MIX_LEN may hold additional flags. */
01630   if (n_cols & 0x80000000UL) {
01631     ulint flags2;
01632 
01633     flags |= DICT_TF_COMPACT;
01634 
01635     field = rec_get_nth_field_old(rec, 7, &len);
01636 
01637     if (UNIV_UNLIKELY(len != 4)) {
01638 
01639       goto err_len;
01640     }
01641 
01642     flags2 = mach_read_from_4(field);
01643 
01644     if (flags2 & (SIZE_MAX << (DICT_TF2_BITS - DICT_TF2_SHIFT))) {
01645       ut_print_timestamp(stderr);
01646       fputs("  InnoDB: Warning: table ", stderr);
01647       ut_print_filename(stderr, name);
01648       fprintf(stderr, "\n"
01649         "InnoDB: in InnoDB data dictionary"
01650         " has unknown flags %lx.\n",
01651         (ulong) flags2);
01652 
01653       flags2 &= ~(~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT));
01654     }
01655 
01656     flags |= flags2 << DICT_TF2_SHIFT;
01657   }
01658 
01659   /* See if the tablespace is available. */
01660   *table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
01661                flags);
01662 
01663   field = rec_get_nth_field_old(rec, 3/*ID*/, &len);
01664   ut_ad(len == 8); /* this was checked earlier */
01665 
01666   (*table)->id = mach_read_from_8(field);
01667 
01668   (*table)->ibd_file_missing = FALSE;
01669 
01670   return(NULL);
01671 }
01672 
01673 /********************************************************************/
01682 UNIV_INTERN
01683 dict_table_t*
01684 dict_load_table(
01685 /*============*/
01686   const char* name, 
01688   ibool   cached) 
01689 {
01690   dict_table_t* table;
01691   dict_table_t* sys_tables;
01692   btr_pcur_t  pcur;
01693   dict_index_t* sys_index;
01694   dtuple_t* tuple;
01695   mem_heap_t* heap;
01696   dfield_t* dfield;
01697   const rec_t*  rec;
01698   const byte* field;
01699   ulint   len;
01700   ulint   err;
01701   const char* err_msg;
01702   mtr_t   mtr;
01703 
01704   ut_ad(mutex_own(&(dict_sys->mutex)));
01705 
01706   heap = mem_heap_create(32000);
01707 
01708   mtr_start(&mtr);
01709 
01710   sys_tables = dict_table_get_low("SYS_TABLES");
01711   sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
01712   ut_a(!dict_table_is_comp(sys_tables));
01713   ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
01714   ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
01715   ut_a(name_of_col_is(sys_tables, sys_index, 5, "TYPE"));
01716   ut_a(name_of_col_is(sys_tables, sys_index, 7, "MIX_LEN"));
01717   ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
01718 
01719   tuple = dtuple_create(heap, 1);
01720   dfield = dtuple_get_nth_field(tuple, 0);
01721 
01722   dfield_set_data(dfield, name, ut_strlen(name));
01723   dict_index_copy_types(tuple, sys_index, 1);
01724 
01725   btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
01726           BTR_SEARCH_LEAF, &pcur, &mtr);
01727   rec = btr_pcur_get_rec(&pcur);
01728 
01729   if (!btr_pcur_is_on_user_rec(&pcur)
01730       || rec_get_deleted_flag(rec, 0)) {
01731     /* Not found */
01732 err_exit:
01733     btr_pcur_close(&pcur);
01734     mtr_commit(&mtr);
01735     mem_heap_free(heap);
01736 
01737     return(NULL);
01738   }
01739 
01740   field = rec_get_nth_field_old(rec, 0, &len);
01741 
01742   /* Check if the table name in record is the searched one */
01743   if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
01744 
01745     goto err_exit;
01746   }
01747 
01748   err_msg = dict_load_table_low(name, rec, &table);
01749 
01750   if (err_msg) {
01751 
01752     ut_print_timestamp(stderr);
01753     fprintf(stderr, "  InnoDB: %s\n", err_msg);
01754     goto err_exit;
01755   }
01756 
01757   if (table->space == 0) {
01758     /* The system tablespace is always available. */
01759   } else if (!fil_space_for_table_exists_in_mem(
01760          table->space, name,
01761          (table->flags >> DICT_TF2_SHIFT)
01762          & DICT_TF2_TEMPORARY,
01763          FALSE, FALSE)) {
01764 
01765     if (table->flags & (DICT_TF2_TEMPORARY << DICT_TF2_SHIFT)) {
01766       /* Do not bother to retry opening temporary tables. */
01767       table->ibd_file_missing = TRUE;
01768     } else {
01769       ut_print_timestamp(stderr);
01770       fprintf(stderr,
01771         "  InnoDB: error: space object of table ");
01772       ut_print_filename(stderr, name);
01773       fprintf(stderr, ",\n"
01774         "InnoDB: space id %lu did not exist in memory."
01775         " Retrying an open.\n",
01776         (ulong) table->space);
01777       /* Try to open the tablespace */
01778       if (!fil_open_single_table_tablespace(
01779         TRUE, table->space,
01780         table->flags == DICT_TF_COMPACT ? 0 :
01781         table->flags & ~(~0 << DICT_TF_BITS), name)) {
01782         /* We failed to find a sensible
01783         tablespace file */
01784 
01785         table->ibd_file_missing = TRUE;
01786       }
01787     }
01788   }
01789 
01790   btr_pcur_close(&pcur);
01791   mtr_commit(&mtr);
01792 
01793   dict_load_columns(table, heap);
01794 
01795   if (cached) {
01796     dict_table_add_to_cache(table, heap);
01797   } else {
01798     dict_table_add_system_columns(table, heap);
01799   }
01800 
01801   mem_heap_empty(heap);
01802 
01803   err = dict_load_indexes(table, heap);
01804 
01805   /* Initialize table foreign_child value. Its value could be
01806   changed when dict_load_foreigns() is called below */
01807   table->fk_max_recusive_level = 0;
01808 
01809   /* If the force recovery flag is set, we open the table irrespective
01810   of the error condition, since the user may want to dump data from the
01811   clustered index. However we load the foreign key information only if
01812   all indexes were loaded. */
01813   if (!cached) {
01814   } else if (err == DB_SUCCESS) {
01815     err = dict_load_foreigns(table->name, TRUE, TRUE);
01816 
01817     if (err != DB_SUCCESS) {
01818       dict_table_remove_from_cache(table);
01819       table = NULL;
01820     } else {
01821       table->fk_max_recusive_level = 0;
01822     }
01823   } else if (!srv_force_recovery) {
01824     dict_table_remove_from_cache(table);
01825     table = NULL;
01826   }
01827 #if 0
01828   if (err != DB_SUCCESS && table != NULL) {
01829 
01830     mutex_enter(&dict_foreign_err_mutex);
01831 
01832     ut_print_timestamp(stderr);
01833 
01834     fprintf(stderr,
01835       "  InnoDB: Error: could not make a foreign key"
01836       " definition to match\n"
01837       "InnoDB: the foreign key table"
01838       " or the referenced table!\n"
01839       "InnoDB: The data dictionary of InnoDB is corrupt."
01840       " You may need to drop\n"
01841       "InnoDB: and recreate the foreign key table"
01842       " or the referenced table.\n"
01843       "InnoDB: Submit a detailed bug report"
01844       " to http://bugs.mysql.com\n"
01845       "InnoDB: Latest foreign key error printout:\n%s\n",
01846       dict_foreign_err_buf);
01847 
01848     mutex_exit(&dict_foreign_err_mutex);
01849   }
01850 #endif /* 0 */
01851   mem_heap_free(heap);
01852 
01853   return(table);
01854 }
01855 
01856 /***********************************************************************/
01859 UNIV_INTERN
01860 dict_table_t*
01861 dict_load_table_on_id(
01862 /*==================*/
01863   table_id_t  table_id) 
01864 {
01865   byte    id_buf[8];
01866   btr_pcur_t  pcur;
01867   mem_heap_t* heap;
01868   dtuple_t* tuple;
01869   dfield_t* dfield;
01870   dict_index_t* sys_table_ids;
01871   dict_table_t* sys_tables;
01872   const rec_t*  rec;
01873   const byte* field;
01874   ulint   len;
01875   dict_table_t* table;
01876   mtr_t   mtr;
01877 
01878   ut_ad(mutex_own(&(dict_sys->mutex)));
01879 
01880   table = NULL;
01881 
01882   /* NOTE that the operation of this function is protected by
01883   the dictionary mutex, and therefore no deadlocks can occur
01884   with other dictionary operations. */
01885 
01886   mtr_start(&mtr);
01887   /*---------------------------------------------------*/
01888   /* Get the secondary index based on ID for table SYS_TABLES */
01889   sys_tables = dict_sys->sys_tables;
01890   sys_table_ids = dict_table_get_next_index(
01891     dict_table_get_first_index(sys_tables));
01892   ut_a(!dict_table_is_comp(sys_tables));
01893   heap = mem_heap_create(256);
01894 
01895   tuple  = dtuple_create(heap, 1);
01896   dfield = dtuple_get_nth_field(tuple, 0);
01897 
01898   /* Write the table id in byte format to id_buf */
01899   mach_write_to_8(id_buf, table_id);
01900 
01901   dfield_set_data(dfield, id_buf, 8);
01902   dict_index_copy_types(tuple, sys_table_ids, 1);
01903 
01904   btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
01905           BTR_SEARCH_LEAF, &pcur, &mtr);
01906   rec = btr_pcur_get_rec(&pcur);
01907 
01908   if (!btr_pcur_is_on_user_rec(&pcur)) {
01909     /* Not found */
01910     goto func_exit;
01911   }
01912 
01913   /* Find the first record that is not delete marked */
01914   while (rec_get_deleted_flag(rec, 0)) {
01915     if (!btr_pcur_move_to_next_user_rec(&pcur, &mtr)) {
01916       goto func_exit;
01917     }
01918     rec = btr_pcur_get_rec(&pcur);
01919   }
01920 
01921   /*---------------------------------------------------*/
01922   /* Now we have the record in the secondary index containing the
01923   table ID and NAME */
01924 
01925   rec = btr_pcur_get_rec(&pcur);
01926   field = rec_get_nth_field_old(rec, 0, &len);
01927   ut_ad(len == 8);
01928 
01929   /* Check if the table id in record is the one searched for */
01930   if (table_id != mach_read_from_8(field)) {
01931     goto func_exit;
01932   }
01933 
01934   /* Now we get the table name from the record */
01935   field = rec_get_nth_field_old(rec, 1, &len);
01936   /* Load the table definition to memory */
01937   table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len),
01938         TRUE);
01939 func_exit:
01940   btr_pcur_close(&pcur);
01941   mtr_commit(&mtr);
01942   mem_heap_free(heap);
01943 
01944   return(table);
01945 }
01946 
01947 /********************************************************************/
01951 UNIV_INTERN
01952 void
01953 dict_load_sys_table(
01954 /*================*/
01955   dict_table_t* table)  
01956 {
01957   mem_heap_t* heap;
01958 
01959   ut_ad(mutex_own(&(dict_sys->mutex)));
01960 
01961   heap = mem_heap_create(1000);
01962 
01963   dict_load_indexes(table, heap);
01964 
01965   mem_heap_free(heap);
01966 }
01967 
01968 /********************************************************************/
01970 static
01971 void
01972 dict_load_foreign_cols(
01973 /*===================*/
01974   const char* id, 
01976   dict_foreign_t* foreign)
01977 {
01978   dict_table_t* sys_foreign_cols;
01979   dict_index_t* sys_index;
01980   btr_pcur_t  pcur;
01981   dtuple_t* tuple;
01982   dfield_t* dfield;
01983   const rec_t*  rec;
01984   const byte* field;
01985   ulint   len;
01986   ulint   i;
01987   mtr_t   mtr;
01988 
01989   ut_ad(mutex_own(&(dict_sys->mutex)));
01990 
01991   foreign->foreign_col_names = static_cast<const char **>(mem_heap_alloc(
01992     foreign->heap, foreign->n_fields * sizeof(void*)));
01993 
01994   foreign->referenced_col_names = static_cast<const char **>(mem_heap_alloc(
01995     foreign->heap, foreign->n_fields * sizeof(void*)));
01996   mtr_start(&mtr);
01997 
01998   sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
01999   sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
02000   ut_a(!dict_table_is_comp(sys_foreign_cols));
02001 
02002   tuple = dtuple_create(foreign->heap, 1);
02003   dfield = dtuple_get_nth_field(tuple, 0);
02004 
02005   dfield_set_data(dfield, id, ut_strlen(id));
02006   dict_index_copy_types(tuple, sys_index, 1);
02007 
02008   btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
02009           BTR_SEARCH_LEAF, &pcur, &mtr);
02010   for (i = 0; i < foreign->n_fields; i++) {
02011 
02012     rec = btr_pcur_get_rec(&pcur);
02013 
02014     ut_a(btr_pcur_is_on_user_rec(&pcur));
02015     ut_a(!rec_get_deleted_flag(rec, 0));
02016 
02017     field = rec_get_nth_field_old(rec, 0, &len);
02018     ut_a(len == ut_strlen(id));
02019     ut_a(ut_memcmp(id, field, len) == 0);
02020 
02021     field = rec_get_nth_field_old(rec, 1, &len);
02022     ut_a(len == 4);
02023     ut_a(i == mach_read_from_4(field));
02024 
02025     field = rec_get_nth_field_old(rec, 4, &len);
02026     foreign->foreign_col_names[i] = mem_heap_strdupl(
02027       foreign->heap, (char*) field, len);
02028 
02029     field = rec_get_nth_field_old(rec, 5, &len);
02030     foreign->referenced_col_names[i] = mem_heap_strdupl(
02031       foreign->heap, (char*) field, len);
02032 
02033     btr_pcur_move_to_next_user_rec(&pcur, &mtr);
02034   }
02035 
02036   btr_pcur_close(&pcur);
02037   mtr_commit(&mtr);
02038 }
02039 
02040 /***********************************************************************/
02043 static
02044 ulint
02045 dict_load_foreign(
02046 /*==============*/
02047   const char* id, 
02049   ibool   check_charsets,
02051   ibool   check_recursive)
02055 {
02056   dict_foreign_t* foreign;
02057   dict_table_t* sys_foreign;
02058   btr_pcur_t  pcur;
02059   dict_index_t* sys_index;
02060   dtuple_t* tuple;
02061   mem_heap_t* heap2;
02062   dfield_t* dfield;
02063   const rec_t*  rec;
02064   const byte* field;
02065   ulint   len;
02066   ulint   n_fields_and_type;
02067   mtr_t   mtr;
02068   dict_table_t* for_table;
02069   dict_table_t* ref_table;
02070 
02071   ut_ad(mutex_own(&(dict_sys->mutex)));
02072 
02073   heap2 = mem_heap_create(1000);
02074 
02075   mtr_start(&mtr);
02076 
02077   sys_foreign = dict_table_get_low("SYS_FOREIGN");
02078   sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
02079   ut_a(!dict_table_is_comp(sys_foreign));
02080 
02081   tuple = dtuple_create(heap2, 1);
02082   dfield = dtuple_get_nth_field(tuple, 0);
02083 
02084   dfield_set_data(dfield, id, ut_strlen(id));
02085   dict_index_copy_types(tuple, sys_index, 1);
02086 
02087   btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
02088           BTR_SEARCH_LEAF, &pcur, &mtr);
02089   rec = btr_pcur_get_rec(&pcur);
02090 
02091   if (!btr_pcur_is_on_user_rec(&pcur)
02092       || rec_get_deleted_flag(rec, 0)) {
02093     /* Not found */
02094 
02095     fprintf(stderr,
02096       "InnoDB: Error A: cannot load foreign constraint %s\n",
02097       id);
02098 
02099     btr_pcur_close(&pcur);
02100     mtr_commit(&mtr);
02101     mem_heap_free(heap2);
02102 
02103     return(DB_ERROR);
02104   }
02105 
02106   field = rec_get_nth_field_old(rec, 0, &len);
02107 
02108   /* Check if the id in record is the searched one */
02109   if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
02110 
02111     fprintf(stderr,
02112       "InnoDB: Error B: cannot load foreign constraint %s\n",
02113       id);
02114 
02115     btr_pcur_close(&pcur);
02116     mtr_commit(&mtr);
02117     mem_heap_free(heap2);
02118 
02119     return(DB_ERROR);
02120   }
02121 
02122   /* Read the table names and the number of columns associated
02123   with the constraint */
02124 
02125   mem_heap_free(heap2);
02126 
02127   foreign = dict_mem_foreign_create();
02128 
02129   n_fields_and_type = mach_read_from_4(
02130     rec_get_nth_field_old(rec, 5, &len));
02131 
02132   ut_a(len == 4);
02133 
02134   /* We store the type in the bits 24..29 of n_fields_and_type. */
02135 
02136   foreign->type = (unsigned int) (n_fields_and_type >> 24);
02137   foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
02138 
02139   foreign->id = mem_heap_strdup(foreign->heap, id);
02140 
02141   field = rec_get_nth_field_old(rec, 3, &len);
02142   foreign->foreign_table_name = mem_heap_strdupl(
02143     foreign->heap, (char*) field, len);
02144 
02145   field = rec_get_nth_field_old(rec, 4, &len);
02146   foreign->referenced_table_name = mem_heap_strdupl(
02147     foreign->heap, (char*) field, len);
02148 
02149   btr_pcur_close(&pcur);
02150   mtr_commit(&mtr);
02151 
02152   dict_load_foreign_cols(id, foreign);
02153 
02154   ref_table = dict_table_check_if_in_cache_low(
02155       foreign->referenced_table_name);
02156 
02157   /* We could possibly wind up in a deep recursive calls if
02158   we call dict_table_get_low() again here if there
02159   is a chain of tables concatenated together with
02160   foreign constraints. In such case, each table is
02161   both a parent and child of the other tables, and
02162   act as a "link" in such table chains.
02163   To avoid such scenario, we would need to check the
02164   number of ancesters the current table has. If that
02165   exceeds DICT_FK_MAX_CHAIN_LEN, we will stop loading
02166   the child table.
02167   Foreign constraints are loaded in a Breath First fashion,
02168   that is, the index on FOR_NAME is scanned first, and then
02169   index on REF_NAME. So foreign constrains in which
02170   current table is a child (foreign table) are loaded first,
02171   and then those constraints where current table is a
02172   parent (referenced) table.
02173   Thus we could check the parent (ref_table) table's
02174   reference count (fk_max_recusive_level) to know how deep the
02175   recursive call is. If the parent table (ref_table) is already
02176   loaded, and its fk_max_recusive_level is larger than
02177   DICT_FK_MAX_CHAIN_LEN, we will stop the recursive loading
02178   by skipping loading the child table. It will not affect foreign
02179   constraint check for DMLs since child table will be loaded
02180   at that time for the constraint check. */
02181   if (!ref_table
02182       || ref_table->fk_max_recusive_level < DICT_FK_MAX_RECURSIVE_LOAD) {
02183 
02184     /* If the foreign table is not yet in the dictionary cache, we
02185     have to load it so that we are able to make type comparisons
02186     in the next function call. */
02187 
02188     for_table = dict_table_get_low(foreign->foreign_table_name);
02189 
02190     if (for_table && ref_table && check_recursive) {
02191       /* This is to record the longest chain of ancesters
02192       this table has, if the parent has more ancesters
02193       than this table has, record it after add 1 (for this
02194       parent */
02195       if (ref_table->fk_max_recusive_level
02196           >= for_table->fk_max_recusive_level) {
02197         for_table->fk_max_recusive_level =
02198            ref_table->fk_max_recusive_level + 1;
02199       }
02200     }
02201   }
02202 
02203   /* Note that there may already be a foreign constraint object in
02204   the dictionary cache for this constraint: then the following
02205   call only sets the pointers in it to point to the appropriate table
02206   and index objects and frees the newly created object foreign.
02207   Adding to the cache should always succeed since we are not creating
02208   a new foreign key constraint but loading one from the data
02209   dictionary. */
02210 
02211   return(dict_foreign_add_to_cache(foreign, check_charsets));
02212 }
02213 
02214 /***********************************************************************/
02221 UNIV_INTERN
02222 ulint
02223 dict_load_foreigns(
02224 /*===============*/
02225   const char* table_name, 
02226   ibool   check_recursive,
02228   ibool   check_charsets) 
02230 {
02231   btr_pcur_t  pcur;
02232   mem_heap_t* heap;
02233   dtuple_t* tuple;
02234   dfield_t* dfield;
02235   dict_index_t* sec_index;
02236   dict_table_t* sys_foreign;
02237   const rec_t*  rec;
02238   const byte* field;
02239   ulint   len;
02240   char*   id ;
02241   ulint   err;
02242   mtr_t   mtr;
02243 
02244   ut_ad(mutex_own(&(dict_sys->mutex)));
02245 
02246   sys_foreign = dict_table_get_low("SYS_FOREIGN");
02247 
02248   if (sys_foreign == NULL) {
02249     /* No foreign keys defined yet in this database */
02250 
02251     fprintf(stderr,
02252       "InnoDB: Error: no foreign key system tables"
02253       " in the database\n");
02254 
02255     return(DB_ERROR);
02256   }
02257 
02258   ut_a(!dict_table_is_comp(sys_foreign));
02259   mtr_start(&mtr);
02260 
02261   /* Get the secondary index based on FOR_NAME from table
02262   SYS_FOREIGN */
02263 
02264   sec_index = dict_table_get_next_index(
02265     dict_table_get_first_index(sys_foreign));
02266 start_load:
02267   heap = mem_heap_create(256);
02268 
02269   tuple  = dtuple_create(heap, 1);
02270   dfield = dtuple_get_nth_field(tuple, 0);
02271 
02272   dfield_set_data(dfield, table_name, ut_strlen(table_name));
02273   dict_index_copy_types(tuple, sec_index, 1);
02274 
02275   btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE,
02276           BTR_SEARCH_LEAF, &pcur, &mtr);
02277 loop:
02278   rec = btr_pcur_get_rec(&pcur);
02279 
02280   if (!btr_pcur_is_on_user_rec(&pcur)) {
02281     /* End of index */
02282 
02283     goto load_next_index;
02284   }
02285 
02286   /* Now we have the record in the secondary index containing a table
02287   name and a foreign constraint ID */
02288 
02289   rec = btr_pcur_get_rec(&pcur);
02290   field = rec_get_nth_field_old(rec, 0, &len);
02291 
02292   /* Check if the table name in the record is the one searched for; the
02293   following call does the comparison in the latin1_swedish_ci
02294   charset-collation, in a case-insensitive way. */
02295 
02296   if (0 != cmp_data_data(dfield_get_type(dfield)->mtype,
02297              dfield_get_type(dfield)->prtype,
02298              static_cast<const unsigned char *>(dfield_get_data(dfield)),
02299                                dfield_get_len(dfield),
02300              field, len)) {
02301 
02302     goto load_next_index;
02303   }
02304 
02305   /* Since table names in SYS_FOREIGN are stored in a case-insensitive
02306   order, we have to check that the table name matches also in a binary
02307   string comparison. On Unix, MySQL allows table names that only differ
02308   in character case. */
02309 
02310   if (0 != ut_memcmp(field, table_name, len)) {
02311 
02312     goto next_rec;
02313   }
02314 
02315   if (rec_get_deleted_flag(rec, 0)) {
02316 
02317     goto next_rec;
02318   }
02319 
02320   /* Now we get a foreign key constraint id */
02321   field = rec_get_nth_field_old(rec, 1, &len);
02322   id = mem_heap_strdupl(heap, (char*) field, len);
02323 
02324   btr_pcur_store_position(&pcur, &mtr);
02325 
02326   mtr_commit(&mtr);
02327 
02328   /* Load the foreign constraint definition to the dictionary cache */
02329 
02330   err = dict_load_foreign(id, check_charsets, check_recursive);
02331 
02332   if (err != DB_SUCCESS) {
02333     btr_pcur_close(&pcur);
02334     mem_heap_free(heap);
02335 
02336     return(err);
02337   }
02338 
02339   mtr_start(&mtr);
02340 
02341   btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
02342 next_rec:
02343   btr_pcur_move_to_next_user_rec(&pcur, &mtr);
02344 
02345   goto loop;
02346 
02347 load_next_index:
02348   btr_pcur_close(&pcur);
02349   mtr_commit(&mtr);
02350   mem_heap_free(heap);
02351 
02352   sec_index = dict_table_get_next_index(sec_index);
02353 
02354   if (sec_index != NULL) {
02355 
02356     mtr_start(&mtr);
02357 
02358     /* Switch to scan index on REF_NAME, fk_max_recusive_level
02359     already been updated when scanning FOR_NAME index, no need to
02360     update again */
02361     check_recursive = FALSE;
02362 
02363     goto start_load;
02364   }
02365 
02366   return(DB_SUCCESS);
02367 }