Drizzled Public API Documentation

dict0dict.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 /******************************************************************/
00026 #include "dict0dict.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "dict0dict.ic"
00030 #endif
00031 
00033 UNIV_INTERN dict_index_t* dict_ind_redundant;
00035 UNIV_INTERN dict_index_t* dict_ind_compact;
00036 
00037 #ifndef UNIV_HOTBACKUP
00038 #include "buf0buf.h"
00039 #include "data0type.h"
00040 #include "mach0data.h"
00041 #include "dict0boot.h"
00042 #include "dict0mem.h"
00043 #include "dict0crea.h"
00044 #include "trx0undo.h"
00045 #include "btr0btr.h"
00046 #include "btr0cur.h"
00047 #include "btr0sea.h"
00048 #include "page0zip.h"
00049 #include "page0page.h"
00050 #include "pars0pars.h"
00051 #include "pars0sym.h"
00052 #include "que0que.h"
00053 #include "rem0cmp.h"
00054 #include "row0merge.h"
00055 #include "ha_prototypes.h" /* innobase_strcasecmp() */
00056 
00057 #include <ctype.h>
00058 
00059 #include <drizzled/session.h>
00060 
00062 UNIV_INTERN dict_sys_t* dict_sys  = NULL;
00063 
00072 UNIV_INTERN rw_lock_t dict_operation_lock;
00073 
00074 /* Keys to register rwlocks and mutexes with performance schema */
00075 #ifdef UNIV_PFS_RWLOCK
00076 UNIV_INTERN mysql_pfs_key_t dict_operation_lock_key;
00077 UNIV_INTERN mysql_pfs_key_t index_tree_rw_lock_key;
00078 #endif /* UNIV_PFS_RWLOCK */
00079 
00080 #ifdef UNIV_PFS_MUTEX
00081 UNIV_INTERN mysql_pfs_key_t dict_sys_mutex_key;
00082 UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key;
00083 #endif /* UNIV_PFS_MUTEX */
00084 
00085 #define DICT_HEAP_SIZE    100 
00087 #define DICT_POOL_PER_TABLE_HASH 512  
00089 #define DICT_POOL_PER_VARYING 4 
00093 static char dict_ibfk[] = "_ibfk_";
00094 
00105 #define DICT_TABLE_STATS_LATCHES_SIZE 64
00106 static rw_lock_t  dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE];
00107 
00108 /*******************************************************************/
00112 static
00113 ibool
00114 dict_index_find_cols(
00115 /*=================*/
00116   dict_table_t* table,  
00117   dict_index_t* index); 
00118 /*******************************************************************/
00122 static
00123 dict_index_t*
00124 dict_index_build_internal_clust(
00125 /*============================*/
00126   const dict_table_t* table,  
00127   dict_index_t*   index); 
00129 /*******************************************************************/
00133 static
00134 dict_index_t*
00135 dict_index_build_internal_non_clust(
00136 /*================================*/
00137   const dict_table_t* table,  
00138   dict_index_t*   index); 
00140 /**********************************************************************/
00142 static
00143 void
00144 dict_foreign_remove_from_cache(
00145 /*===========================*/
00146   dict_foreign_t* foreign); 
00147 /**********************************************************************/
00149 static
00150 void
00151 dict_col_print_low(
00152 /*===============*/
00153   const dict_table_t* table,  
00154   const dict_col_t* col); 
00155 /**********************************************************************/
00157 static
00158 void
00159 dict_index_print_low(
00160 /*=================*/
00161   dict_index_t* index); 
00162 /**********************************************************************/
00164 static
00165 void
00166 dict_field_print_low(
00167 /*=================*/
00168   const dict_field_t* field); 
00169 /*********************************************************************/
00171 static
00172 void
00173 dict_foreign_free(
00174 /*==============*/
00175   dict_foreign_t* foreign); 
00177 /* Stream for storing detailed information about the latest foreign key
00178 and unique key errors */
00179 UNIV_INTERN FILE* dict_foreign_err_file   = NULL;
00180 /* mutex protecting the foreign and unique error buffers */
00181 UNIV_INTERN mutex_t dict_foreign_err_mutex;
00182 
00183 /******************************************************************/
00185 UNIV_INTERN
00186 void
00187 dict_casedn_str(
00188 /*============*/
00189   char* a)  
00190 {
00191   innobase_casedn_str(a);
00192 }
00193 
00194 /********************************************************************/
00197 UNIV_INTERN
00198 ibool
00199 dict_tables_have_same_db(
00200 /*=====================*/
00201   const char* name1,  
00203   const char* name2)  
00205 {
00206   for (; *name1 == *name2; name1++, name2++) {
00207     if (*name1 == '/') {
00208       return(TRUE);
00209     }
00210     ut_a(*name1); /* the names must contain '/' */
00211   }
00212   return(FALSE);
00213 }
00214 
00215 /********************************************************************/
00218 UNIV_INTERN
00219 const char*
00220 dict_remove_db_name(
00221 /*================*/
00222   const char* name) 
00224 {
00225   const char* s = strchr(name, '/');
00226   ut_a(s);
00227 
00228   return(s + 1);
00229 }
00230 
00231 /********************************************************************/
00234 UNIV_INTERN
00235 ulint
00236 dict_get_db_name_len(
00237 /*=================*/
00238   const char* name) 
00240 {
00241   const char* s;
00242   s = strchr(name, '/');
00243   ut_a(s);
00244   return(s - name);
00245 }
00246 
00247 /********************************************************************/
00249 UNIV_INTERN
00250 void
00251 dict_mutex_enter_for_mysql(void)
00252 /*============================*/
00253 {
00254   mutex_enter(&(dict_sys->mutex));
00255 }
00256 
00257 /********************************************************************/
00259 UNIV_INTERN
00260 void
00261 dict_mutex_exit_for_mysql(void)
00262 /*===========================*/
00263 {
00264   mutex_exit(&(dict_sys->mutex));
00265 }
00266 
00268 #define GET_TABLE_STATS_LATCH(table) \
00269   (&dict_table_stats_latches[ut_fold_ull(table->id) \
00270            % DICT_TABLE_STATS_LATCHES_SIZE])
00271 
00272 /**********************************************************************/
00276 UNIV_INTERN
00277 void
00278 dict_table_stats_lock(
00279 /*==================*/
00280   const dict_table_t* table,    
00281   ulint     latch_mode) 
00283 {
00284   ut_ad(table != NULL);
00285   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
00286 
00287   switch (latch_mode) {
00288   case RW_S_LATCH:
00289     rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
00290     break;
00291   case RW_X_LATCH:
00292     rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
00293     break;
00294   case RW_NO_LATCH:
00295     /* fall through */
00296   default:
00297     ut_error;
00298   }
00299 }
00300 
00301 /**********************************************************************/
00303 UNIV_INTERN
00304 void
00305 dict_table_stats_unlock(
00306 /*====================*/
00307   const dict_table_t* table,    
00308   ulint     latch_mode) 
00310 {
00311   ut_ad(table != NULL);
00312   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
00313 
00314   switch (latch_mode) {
00315   case RW_S_LATCH:
00316     rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
00317     break;
00318   case RW_X_LATCH:
00319     rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
00320     break;
00321   case RW_NO_LATCH:
00322     /* fall through */
00323   default:
00324     ut_error;
00325   }
00326 }
00327 
00328 /********************************************************************/
00330 UNIV_INTERN
00331 void
00332 dict_table_decrement_handle_count(
00333 /*==============================*/
00334   dict_table_t* table,    
00335   ibool   dict_locked)  
00336 {
00337   if (!dict_locked) {
00338     mutex_enter(&dict_sys->mutex);
00339   }
00340 
00341   ut_ad(mutex_own(&dict_sys->mutex));
00342   ut_a(table->n_mysql_handles_opened > 0);
00343 
00344   table->n_mysql_handles_opened--;
00345 
00346   if (!dict_locked) {
00347     mutex_exit(&dict_sys->mutex);
00348   }
00349 }
00350 #endif /* !UNIV_HOTBACKUP */
00351 
00352 /**********************************************************************/
00356 UNIV_INTERN
00357 const char*
00358 dict_table_get_col_name(
00359 /*====================*/
00360   const dict_table_t* table,  
00361   ulint     col_nr) 
00362 {
00363   ulint   i;
00364   const char* s;
00365 
00366   ut_ad(table);
00367   ut_ad(col_nr < table->n_def);
00368   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
00369 
00370   s = table->col_names;
00371   if (s) {
00372     for (i = 0; i < col_nr; i++) {
00373       s += strlen(s) + 1;
00374     }
00375   }
00376 
00377   return(s);
00378 }
00379 
00380 #ifndef UNIV_HOTBACKUP
00381 /********************************************************************/
00383 UNIV_INTERN
00384 void
00385 dict_table_autoinc_lock(
00386 /*====================*/
00387   dict_table_t* table)  
00388 {
00389   mutex_enter(&table->autoinc_mutex);
00390 }
00391 
00392 /********************************************************************/
00394 UNIV_INTERN
00395 void
00396 dict_table_autoinc_initialize(
00397 /*==========================*/
00398   dict_table_t* table,  
00399   ib_uint64_t value)  
00400 {
00401   ut_ad(mutex_own(&table->autoinc_mutex));
00402 
00403   table->autoinc = value;
00404 }
00405 
00406 /********************************************************************/
00410 UNIV_INTERN
00411 ib_uint64_t
00412 dict_table_autoinc_read(
00413 /*====================*/
00414   const dict_table_t* table)  
00415 {
00416   ut_ad(mutex_own(&table->autoinc_mutex));
00417 
00418   return(table->autoinc);
00419 }
00420 
00421 /********************************************************************/
00424 UNIV_INTERN
00425 void
00426 dict_table_autoinc_update_if_greater(
00427 /*=================================*/
00428 
00429   dict_table_t* table,  
00430   ib_uint64_t value)  
00431 {
00432   ut_ad(mutex_own(&table->autoinc_mutex));
00433 
00434   if (value > table->autoinc) {
00435 
00436     table->autoinc = value;
00437   }
00438 }
00439 
00440 /********************************************************************/
00442 UNIV_INTERN
00443 void
00444 dict_table_autoinc_unlock(
00445 /*======================*/
00446   dict_table_t* table)  
00447 {
00448   mutex_exit(&table->autoinc_mutex);
00449 }
00450 
00451 /**********************************************************************/
00455 UNIV_INTERN
00456 dict_index_t*
00457 dict_index_get_on_id_low(
00458 /*=====================*/
00459   dict_table_t* table,  
00460   index_id_t  id) 
00461 {
00462   dict_index_t* index;
00463 
00464   index = dict_table_get_first_index(table);
00465 
00466   while (index) {
00467     if (id == index->id) {
00468       /* Found */
00469 
00470       return(index);
00471     }
00472 
00473     index = dict_table_get_next_index(index);
00474   }
00475 
00476   return(NULL);
00477 }
00478 #endif /* !UNIV_HOTBACKUP */
00479 
00480 /********************************************************************/
00484 UNIV_INTERN
00485 ulint
00486 dict_index_get_nth_col_pos(
00487 /*=======================*/
00488   const dict_index_t* index,  
00489   ulint     n)  
00490 {
00491   const dict_field_t* field;
00492   const dict_col_t* col;
00493   ulint     pos;
00494   ulint     n_fields;
00495 
00496   ut_ad(index);
00497   ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
00498 
00499   col = dict_table_get_nth_col(index->table, n);
00500 
00501   if (dict_index_is_clust(index)) {
00502 
00503     return(dict_col_get_clust_pos(col, index));
00504   }
00505 
00506   n_fields = dict_index_get_n_fields(index);
00507 
00508   for (pos = 0; pos < n_fields; pos++) {
00509     field = dict_index_get_nth_field(index, pos);
00510 
00511     if (col == field->col && field->prefix_len == 0) {
00512 
00513       return(pos);
00514     }
00515   }
00516 
00517   return(ULINT_UNDEFINED);
00518 }
00519 
00520 #ifndef UNIV_HOTBACKUP
00521 /********************************************************************/
00524 UNIV_INTERN
00525 ibool
00526 dict_index_contains_col_or_prefix(
00527 /*==============================*/
00528   const dict_index_t* index,  
00529   ulint     n)  
00530 {
00531   const dict_field_t* field;
00532   const dict_col_t* col;
00533   ulint     pos;
00534   ulint     n_fields;
00535 
00536   ut_ad(index);
00537   ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
00538 
00539   if (dict_index_is_clust(index)) {
00540 
00541     return(TRUE);
00542   }
00543 
00544   col = dict_table_get_nth_col(index->table, n);
00545 
00546   n_fields = dict_index_get_n_fields(index);
00547 
00548   for (pos = 0; pos < n_fields; pos++) {
00549     field = dict_index_get_nth_field(index, pos);
00550 
00551     if (col == field->col) {
00552 
00553       return(TRUE);
00554     }
00555   }
00556 
00557   return(FALSE);
00558 }
00559 
00560 /********************************************************************/
00567 UNIV_INTERN
00568 ulint
00569 dict_index_get_nth_field_pos(
00570 /*=========================*/
00571   const dict_index_t* index,  
00572   const dict_index_t* index2, 
00573   ulint     n)  
00574 {
00575   const dict_field_t* field;
00576   const dict_field_t* field2;
00577   ulint     n_fields;
00578   ulint     pos;
00579 
00580   ut_ad(index);
00581   ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
00582 
00583   field2 = dict_index_get_nth_field(index2, n);
00584 
00585   n_fields = dict_index_get_n_fields(index);
00586 
00587   for (pos = 0; pos < n_fields; pos++) {
00588     field = dict_index_get_nth_field(index, pos);
00589 
00590     if (field->col == field2->col
00591         && (field->prefix_len == 0
00592       || (field->prefix_len >= field2->prefix_len
00593           && field2->prefix_len != 0))) {
00594 
00595       return(pos);
00596     }
00597   }
00598 
00599   return(ULINT_UNDEFINED);
00600 }
00601 
00602 /**********************************************************************/
00605 UNIV_INTERN
00606 dict_table_t*
00607 dict_table_get_on_id(
00608 /*=================*/
00609   table_id_t  table_id, 
00610   trx_t*    trx)    
00611 {
00612   dict_table_t* table;
00613 
00614   if (trx->dict_operation_lock_mode == RW_X_LATCH) {
00615 
00616     /* Note: An X latch implies that the transaction
00617     already owns the dictionary mutex. */
00618 
00619     ut_ad(mutex_own(&dict_sys->mutex));
00620 
00621     return(dict_table_get_on_id_low(table_id));
00622   }
00623 
00624   mutex_enter(&(dict_sys->mutex));
00625 
00626   table = dict_table_get_on_id_low(table_id);
00627 
00628   mutex_exit(&(dict_sys->mutex));
00629 
00630   return(table);
00631 }
00632 
00633 /********************************************************************/
00636 UNIV_INTERN
00637 ulint
00638 dict_table_get_nth_col_pos(
00639 /*=======================*/
00640   const dict_table_t* table,  
00641   ulint     n)  
00642 {
00643   return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
00644             n));
00645 }
00646 
00647 /********************************************************************/
00651 UNIV_INTERN
00652 ibool
00653 dict_table_col_in_clustered_key(
00654 /*============================*/
00655   const dict_table_t* table,  
00656   ulint     n)  
00657 {
00658   const dict_index_t* index;
00659   const dict_field_t* field;
00660   const dict_col_t* col;
00661   ulint     pos;
00662   ulint     n_fields;
00663 
00664   ut_ad(table);
00665 
00666   col = dict_table_get_nth_col(table, n);
00667 
00668   index = dict_table_get_first_index(table);
00669 
00670   n_fields = dict_index_get_n_unique(index);
00671 
00672   for (pos = 0; pos < n_fields; pos++) {
00673     field = dict_index_get_nth_field(index, pos);
00674 
00675     if (col == field->col) {
00676 
00677       return(TRUE);
00678     }
00679   }
00680 
00681   return(FALSE);
00682 }
00683 
00684 /**********************************************************************/
00686 UNIV_INTERN
00687 void
00688 dict_init(void)
00689 /*===========*/
00690 {
00691   int i;
00692 
00693   dict_sys = static_cast<dict_sys_t *>(mem_alloc(sizeof(dict_sys_t)));
00694 
00695   mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
00696 
00697   dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
00698              / (DICT_POOL_PER_TABLE_HASH
00699                 * UNIV_WORD_SIZE));
00700   dict_sys->table_id_hash = hash_create(buf_pool_get_curr_size()
00701                 / (DICT_POOL_PER_TABLE_HASH
00702              * UNIV_WORD_SIZE));
00703   dict_sys->size = 0;
00704 
00705   UT_LIST_INIT(dict_sys->table_LRU);
00706 
00707   rw_lock_create(dict_operation_lock_key,
00708            &dict_operation_lock, SYNC_DICT_OPERATION);
00709 
00710   dict_foreign_err_file = os_file_create_tmpfile();
00711   ut_a(dict_foreign_err_file);
00712 
00713   mutex_create(dict_foreign_err_mutex_key,
00714          &dict_foreign_err_mutex, SYNC_ANY_LATCH);
00715 
00716   for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
00717     rw_lock_create(PFS_NOT_INSTRUMENTED,
00718              &dict_table_stats_latches[i], SYNC_INDEX_TREE);
00719         }
00720 }
00721 
00722 /**********************************************************************/
00728 UNIV_INTERN
00729 dict_table_t*
00730 dict_table_get(
00731 /*===========*/
00732   const char* table_name, 
00733   ibool   inc_mysql_count)
00735 {
00736   dict_table_t* table;
00737 
00738   mutex_enter(&(dict_sys->mutex));
00739 
00740   table = dict_table_get_low(table_name);
00741 
00742   if (inc_mysql_count && table) {
00743     table->n_mysql_handles_opened++;
00744   }
00745 
00746   mutex_exit(&(dict_sys->mutex));
00747 
00748   if (table != NULL) {
00749     /* If table->ibd_file_missing == TRUE, this will
00750     print an error message and return without doing
00751     anything. */
00752     dict_update_statistics(table, TRUE /* only update stats
00753                if they have not been initialized */);
00754   }
00755 
00756   return(table);
00757 }
00758 #endif /* !UNIV_HOTBACKUP */
00759 
00760 /**********************************************************************/
00762 UNIV_INTERN
00763 void
00764 dict_table_add_system_columns(
00765 /*==========================*/
00766   dict_table_t* table,  
00767   mem_heap_t* heap) 
00768 {
00769   ut_ad(table);
00770   ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
00771   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
00772   ut_ad(!table->cached);
00773 
00774   /* NOTE: the system columns MUST be added in the following order
00775   (so that they can be indexed by the numerical value of DATA_ROW_ID,
00776   etc.) and as the last columns of the table memory object.
00777   The clustered index will not always physically contain all
00778   system columns. */
00779 
00780   dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
00781              DATA_ROW_ID | DATA_NOT_NULL,
00782              DATA_ROW_ID_LEN);
00783 #if DATA_ROW_ID != 0
00784 #error "DATA_ROW_ID != 0"
00785 #endif
00786   dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
00787              DATA_TRX_ID | DATA_NOT_NULL,
00788              DATA_TRX_ID_LEN);
00789 #if DATA_TRX_ID != 1
00790 #error "DATA_TRX_ID != 1"
00791 #endif
00792   dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
00793              DATA_ROLL_PTR | DATA_NOT_NULL,
00794              DATA_ROLL_PTR_LEN);
00795 #if DATA_ROLL_PTR != 2
00796 #error "DATA_ROLL_PTR != 2"
00797 #endif
00798 
00799   /* This check reminds that if a new system column is added to
00800   the program, it should be dealt with here */
00801 #if DATA_N_SYS_COLS != 3
00802 #error "DATA_N_SYS_COLS != 3"
00803 #endif
00804 }
00805 
00806 #ifndef UNIV_HOTBACKUP
00807 /**********************************************************************/
00809 UNIV_INTERN
00810 void
00811 dict_table_add_to_cache(
00812 /*====================*/
00813   dict_table_t* table,  
00814   mem_heap_t* heap) 
00815 {
00816   ulint fold;
00817   ulint id_fold;
00818   ulint i;
00819   ulint row_len;
00820 
00821   /* The lower limit for what we consider a "big" row */
00822 #define BIG_ROW_SIZE 1024
00823 
00824   ut_ad(mutex_own(&(dict_sys->mutex)));
00825 
00826   dict_table_add_system_columns(table, heap);
00827 
00828   table->cached = TRUE;
00829 
00830   fold = ut_fold_string(table->name);
00831   id_fold = ut_fold_ull(table->id);
00832 
00833   row_len = 0;
00834   for (i = 0; i < table->n_def; i++) {
00835     ulint col_len = dict_col_get_max_size(
00836       dict_table_get_nth_col(table, i));
00837 
00838     row_len += col_len;
00839 
00840     /* If we have a single unbounded field, or several gigantic
00841     fields, mark the maximum row size as BIG_ROW_SIZE. */
00842     if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
00843       row_len = BIG_ROW_SIZE;
00844 
00845       break;
00846     }
00847   }
00848 
00849   table->big_rows = row_len >= BIG_ROW_SIZE;
00850 
00851   /* Look for a table with the same name: error if such exists */
00852   {
00853     dict_table_t* table2;
00854     HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
00855           dict_table_t*, table2, ut_ad(table2->cached),
00856           ut_strcmp(table2->name, table->name) == 0);
00857     ut_a(table2 == NULL);
00858 
00859 #ifdef UNIV_DEBUG
00860     /* Look for the same table pointer with a different name */
00861     HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
00862         dict_table_t*, table2, ut_ad(table2->cached),
00863         table2 == table);
00864     ut_ad(table2 == NULL);
00865 #endif /* UNIV_DEBUG */
00866   }
00867 
00868   /* Look for a table with the same id: error if such exists */
00869   {
00870     dict_table_t* table2;
00871     HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
00872           dict_table_t*, table2, ut_ad(table2->cached),
00873           table2->id == table->id);
00874     ut_a(table2 == NULL);
00875 
00876 #ifdef UNIV_DEBUG
00877     /* Look for the same table pointer with a different id */
00878     HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
00879         dict_table_t*, table2, ut_ad(table2->cached),
00880         table2 == table);
00881     ut_ad(table2 == NULL);
00882 #endif /* UNIV_DEBUG */
00883   }
00884 
00885   /* Add table to hash table of tables */
00886   HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
00887         table);
00888 
00889   /* Add table to hash table of tables based on table id */
00890   HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
00891         table);
00892   /* Add table to LRU list of tables */
00893   UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
00894 
00895   dict_sys->size += mem_heap_get_size(table->heap)
00896     + strlen(table->name) + 1;
00897 }
00898 
00899 /**********************************************************************/
00904 UNIV_INTERN
00905 dict_index_t*
00906 dict_index_find_on_id_low(
00907 /*======================*/
00908   index_id_t  id) 
00909 {
00910   dict_table_t* table;
00911   dict_index_t* index;
00912 
00913   table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
00914 
00915   while (table) {
00916     index = dict_table_get_first_index(table);
00917 
00918     while (index) {
00919       if (id == index->id) {
00920         /* Found */
00921 
00922         return(index);
00923       }
00924 
00925       index = dict_table_get_next_index(index);
00926     }
00927 
00928     table = UT_LIST_GET_NEXT(table_LRU, table);
00929   }
00930 
00931   return(NULL);
00932 }
00933 
00934 /**********************************************************************/
00937 UNIV_INTERN
00938 ibool
00939 dict_table_rename_in_cache(
00940 /*=======================*/
00941   dict_table_t* table,    
00942   const char* new_name, 
00943   ibool   rename_also_foreigns)
00946 {
00947   dict_foreign_t* foreign;
00948   dict_index_t* index;
00949   ulint   fold;
00950   char    old_name[MAX_TABLE_NAME_LEN + 1];
00951 
00952   ut_ad(table);
00953   ut_ad(mutex_own(&(dict_sys->mutex)));
00954 
00955   /* store the old/current name to an automatic variable */
00956   if (strlen(table->name) + 1 <= sizeof(old_name)) {
00957     memcpy(old_name, table->name, strlen(table->name) + 1);
00958   } else {
00959     ut_print_timestamp(stderr);
00960     fprintf(stderr, "InnoDB: too long table name: '%s', "
00961       "max length is %d\n", table->name,
00962       MAX_TABLE_NAME_LEN);
00963     ut_error;
00964   }
00965 
00966   fold = ut_fold_string(new_name);
00967 
00968   /* Look for a table with the same name: error if such exists */
00969   {
00970     dict_table_t* table2;
00971     HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
00972           dict_table_t*, table2, ut_ad(table2->cached),
00973           (ut_strcmp(table2->name, new_name) == 0));
00974     if (UNIV_LIKELY_NULL(table2)) {
00975       ut_print_timestamp(stderr);
00976       fputs("  InnoDB: Error: dictionary cache"
00977             " already contains a table ", stderr);
00978       ut_print_name(stderr, NULL, TRUE, new_name);
00979       fputs("\n"
00980             "InnoDB: cannot rename table ", stderr);
00981       ut_print_name(stderr, NULL, TRUE, old_name);
00982       putc('\n', stderr);
00983       return(FALSE);
00984     }
00985   }
00986 
00987   /* If the table is stored in a single-table tablespace, rename the
00988   .ibd file */
00989 
00990   if (table->space != 0) {
00991     if (table->dir_path_of_temp_table != NULL) {
00992       ut_print_timestamp(stderr);
00993       fputs("  InnoDB: Error: trying to rename a"
00994             " TEMPORARY TABLE ", stderr);
00995       ut_print_name(stderr, NULL, TRUE, old_name);
00996       fputs(" (", stderr);
00997       ut_print_filename(stderr,
00998             table->dir_path_of_temp_table);
00999       fputs(" )\n", stderr);
01000       return(FALSE);
01001     } else if (!fil_rename_tablespace(old_name, table->space,
01002               new_name)) {
01003       return(FALSE);
01004     }
01005   }
01006 
01007   /* Remove table from the hash tables of tables */
01008   HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
01009         ut_fold_string(old_name), table);
01010 
01011   if (strlen(new_name) > strlen(table->name)) {
01012     /* We allocate MAX_TABLE_NAME_LEN+1 bytes here to avoid
01013     memory fragmentation, we assume a repeated calls of
01014     ut_realloc() with the same size do not cause fragmentation */
01015     ut_a(strlen(new_name) <= MAX_TABLE_NAME_LEN);
01016     table->name = static_cast<char *>(ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1));
01017   }
01018   memcpy(table->name, new_name, strlen(new_name) + 1);
01019 
01020   /* Add table to hash table of tables */
01021   HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
01022         table);
01023 
01024   dict_sys->size += strlen(new_name) - strlen(old_name);
01025   ut_a(dict_sys->size > 0);
01026 
01027   /* Update the table_name field in indexes */
01028   index = dict_table_get_first_index(table);
01029 
01030   while (index != NULL) {
01031     index->table_name = table->name;
01032 
01033     index = dict_table_get_next_index(index);
01034   }
01035 
01036   if (!rename_also_foreigns) {
01037     /* In ALTER TABLE we think of the rename table operation
01038     in the direction table -> temporary table (#sql...)
01039     as dropping the table with the old name and creating
01040     a new with the new name. Thus we kind of drop the
01041     constraints from the dictionary cache here. The foreign key
01042     constraints will be inherited to the new table from the
01043     system tables through a call of dict_load_foreigns. */
01044 
01045     /* Remove the foreign constraints from the cache */
01046     foreign = UT_LIST_GET_LAST(table->foreign_list);
01047 
01048     while (foreign != NULL) {
01049       dict_foreign_remove_from_cache(foreign);
01050       foreign = UT_LIST_GET_LAST(table->foreign_list);
01051     }
01052 
01053     /* Reset table field in referencing constraints */
01054 
01055     foreign = UT_LIST_GET_FIRST(table->referenced_list);
01056 
01057     while (foreign != NULL) {
01058       foreign->referenced_table = NULL;
01059       foreign->referenced_index = NULL;
01060 
01061       foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
01062     }
01063 
01064     /* Make the list of referencing constraints empty */
01065 
01066     UT_LIST_INIT(table->referenced_list);
01067 
01068     return(TRUE);
01069   }
01070 
01071   /* Update the table name fields in foreign constraints, and update also
01072   the constraint id of new format >= 4.0.18 constraints. Note that at
01073   this point we have already changed table->name to the new name. */
01074 
01075   foreign = UT_LIST_GET_FIRST(table->foreign_list);
01076 
01077   while (foreign != NULL) {
01078     if (ut_strlen(foreign->foreign_table_name)
01079         < ut_strlen(table->name)) {
01080       /* Allocate a longer name buffer;
01081       TODO: store buf len to save memory */
01082 
01083       foreign->foreign_table_name
01084         = static_cast<char *>(mem_heap_alloc(foreign->heap,
01085              ut_strlen(table->name) + 1));
01086     }
01087 
01088     strcpy(foreign->foreign_table_name, table->name);
01089 
01090     if (strchr(foreign->id, '/')) {
01091       ulint db_len;
01092       char* old_id;
01093 
01094       /* This is a >= 4.0.18 format id */
01095 
01096       old_id = mem_strdup(foreign->id);
01097 
01098       if (ut_strlen(foreign->id) > ut_strlen(old_name)
01099           + ((sizeof dict_ibfk) - 1)
01100           && !memcmp(foreign->id, old_name,
01101                ut_strlen(old_name))
01102           && !memcmp(foreign->id + ut_strlen(old_name),
01103                dict_ibfk, (sizeof dict_ibfk) - 1)) {
01104 
01105         /* This is a generated >= 4.0.18 format id */
01106 
01107         if (strlen(table->name) > strlen(old_name)) {
01108           foreign->id = static_cast<char *>(mem_heap_alloc(
01109             foreign->heap,
01110             strlen(table->name)
01111             + strlen(old_id) + 1));
01112         }
01113 
01114         /* Replace the prefix 'databasename/tablename'
01115         with the new names */
01116         strcpy(foreign->id, table->name);
01117         strcat(foreign->id,
01118                old_id + ut_strlen(old_name));
01119       } else {
01120         /* This is a >= 4.0.18 format id where the user
01121         gave the id name */
01122         db_len = dict_get_db_name_len(table->name) + 1;
01123 
01124         if (dict_get_db_name_len(table->name)
01125             > dict_get_db_name_len(foreign->id)) {
01126 
01127           foreign->id = static_cast<char *>(mem_heap_alloc(
01128             foreign->heap,
01129             db_len + strlen(old_id) + 1));
01130         }
01131 
01132         /* Replace the database prefix in id with the
01133         one from table->name */
01134 
01135         ut_memcpy(foreign->id, table->name, db_len);
01136 
01137         strcpy(foreign->id + db_len,
01138                dict_remove_db_name(old_id));
01139       }
01140 
01141       mem_free(old_id);
01142     }
01143 
01144     foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
01145   }
01146 
01147   foreign = UT_LIST_GET_FIRST(table->referenced_list);
01148 
01149   while (foreign != NULL) {
01150     if (ut_strlen(foreign->referenced_table_name)
01151         < ut_strlen(table->name)) {
01152       /* Allocate a longer name buffer;
01153       TODO: store buf len to save memory */
01154 
01155       foreign->referenced_table_name = static_cast<char *>(mem_heap_alloc(
01156         foreign->heap, strlen(table->name) + 1));
01157     }
01158 
01159     strcpy(foreign->referenced_table_name, table->name);
01160 
01161     foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
01162   }
01163 
01164   return(TRUE);
01165 }
01166 
01167 /**********************************************************************/
01170 UNIV_INTERN
01171 void
01172 dict_table_change_id_in_cache(
01173 /*==========================*/
01174   dict_table_t* table,  
01175   table_id_t  new_id) 
01176 {
01177   ut_ad(table);
01178   ut_ad(mutex_own(&(dict_sys->mutex)));
01179   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
01180 
01181   /* Remove the table from the hash table of id's */
01182 
01183   HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
01184         ut_fold_ull(table->id), table);
01185   table->id = new_id;
01186 
01187   /* Add the table back to the hash table */
01188   HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
01189         ut_fold_ull(table->id), table);
01190 }
01191 
01192 /**********************************************************************/
01194 UNIV_INTERN
01195 void
01196 dict_table_remove_from_cache(
01197 /*=========================*/
01198   dict_table_t* table)  
01199 {
01200   dict_foreign_t* foreign;
01201   dict_index_t* index;
01202   ulint   size;
01203 
01204   ut_ad(table);
01205   ut_ad(mutex_own(&(dict_sys->mutex)));
01206   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
01207 
01208 #if 0
01209   fputs("Removing table ", stderr);
01210   ut_print_name(stderr, table->name, ULINT_UNDEFINED);
01211   fputs(" from dictionary cache\n", stderr);
01212 #endif
01213 
01214   /* Remove the foreign constraints from the cache */
01215   foreign = UT_LIST_GET_LAST(table->foreign_list);
01216 
01217   while (foreign != NULL) {
01218     dict_foreign_remove_from_cache(foreign);
01219     foreign = UT_LIST_GET_LAST(table->foreign_list);
01220   }
01221 
01222   /* Reset table field in referencing constraints */
01223 
01224   foreign = UT_LIST_GET_FIRST(table->referenced_list);
01225 
01226   while (foreign != NULL) {
01227     foreign->referenced_table = NULL;
01228     foreign->referenced_index = NULL;
01229 
01230     foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
01231   }
01232 
01233   /* Remove the indexes from the cache */
01234   index = UT_LIST_GET_LAST(table->indexes);
01235 
01236   while (index != NULL) {
01237     dict_index_remove_from_cache(table, index);
01238     index = UT_LIST_GET_LAST(table->indexes);
01239   }
01240 
01241   /* Remove table from the hash tables of tables */
01242   HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
01243         ut_fold_string(table->name), table);
01244   HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
01245         ut_fold_ull(table->id), table);
01246 
01247   /* Remove table from LRU list of tables */
01248   UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
01249 
01250   size = mem_heap_get_size(table->heap) + strlen(table->name) + 1;
01251 
01252   ut_ad(dict_sys->size >= size);
01253 
01254   dict_sys->size -= size;
01255 
01256   dict_mem_table_free(table);
01257 }
01258 
01259 /****************************************************************/
01263 UNIV_INTERN
01264 ibool
01265 dict_col_name_is_reserved(
01266 /*======================*/
01267   const char* name) 
01268 {
01269   /* This check reminds that if a new system column is added to
01270   the program, it should be dealt with here. */
01271 #if DATA_N_SYS_COLS != 3
01272 #error "DATA_N_SYS_COLS != 3"
01273 #endif
01274 
01275   static const char*  reserved_names[] = {
01276     "DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
01277   };
01278 
01279   ulint     i;
01280 
01281   for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
01282     if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
01283 
01284       return(TRUE);
01285     }
01286   }
01287 
01288   return(FALSE);
01289 }
01290 
01291 /****************************************************************/
01295 static
01296 ibool
01297 dict_index_too_big_for_undo(
01298 /*========================*/
01299   const dict_table_t* table,    
01300   const dict_index_t* new_index)  
01301 {
01302   /* Make sure that all column prefixes will fit in the undo log record
01303   in trx_undo_page_report_modify() right after trx_undo_page_init(). */
01304 
01305   ulint     i;
01306   const dict_index_t* clust_index
01307     = dict_table_get_first_index(table);
01308   ulint     undo_page_len
01309     = TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
01310     + 2 /* next record pointer */
01311     + 1 /* type_cmpl */
01312     + 11 /* trx->undo_no */ + 11 /* table->id */
01313     + 1 /* rec_get_info_bits() */
01314     + 11 /* DB_TRX_ID */
01315     + 11 /* DB_ROLL_PTR */
01316     + 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
01317     + 2/* pointer to previous undo log record */;
01318 
01319   if (UNIV_UNLIKELY(!clust_index)) {
01320     ut_a(dict_index_is_clust(new_index));
01321     clust_index = new_index;
01322   }
01323 
01324   /* Add the size of the ordering columns in the
01325   clustered index. */
01326   for (i = 0; i < clust_index->n_uniq; i++) {
01327     const dict_col_t* col
01328       = dict_index_get_nth_col(clust_index, i);
01329 
01330     /* Use the maximum output size of
01331     mach_write_compressed(), although the encoded
01332     length should always fit in 2 bytes. */
01333     undo_page_len += 5 + dict_col_get_max_size(col);
01334   }
01335 
01336   /* Add the old values of the columns to be updated.
01337   First, the amount and the numbers of the columns.
01338   These are written by mach_write_compressed() whose
01339   maximum output length is 5 bytes.  However, given that
01340   the quantities are below REC_MAX_N_FIELDS (10 bits),
01341   the maximum length is 2 bytes per item. */
01342   undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);
01343 
01344   for (i = 0; i < clust_index->n_def; i++) {
01345     const dict_col_t* col
01346       = dict_index_get_nth_col(clust_index, i);
01347     ulint     max_size
01348       = dict_col_get_max_size(col);
01349     ulint     fixed_size
01350       = dict_col_get_fixed_size(col,
01351               dict_table_is_comp(table));
01352 
01353     if (fixed_size) {
01354       /* Fixed-size columns are stored locally. */
01355       max_size = fixed_size;
01356     } else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
01357       /* Short columns are stored locally. */
01358     } else if (!col->ord_part) {
01359       /* See if col->ord_part would be set
01360       because of new_index. */
01361       ulint j;
01362 
01363       for (j = 0; j < new_index->n_uniq; j++) {
01364         if (dict_index_get_nth_col(
01365               new_index, j) == col) {
01366 
01367           goto is_ord_part;
01368         }
01369       }
01370 
01371       /* This is not an ordering column in any index.
01372       Thus, it can be stored completely externally. */
01373       max_size = BTR_EXTERN_FIELD_REF_SIZE;
01374     } else {
01375 is_ord_part:
01376       /* This is an ordering column in some index.
01377       A long enough prefix must be written to the
01378       undo log.  See trx_undo_page_fetch_ext(). */
01379 
01380       if (max_size > REC_MAX_INDEX_COL_LEN) {
01381         max_size = REC_MAX_INDEX_COL_LEN;
01382       }
01383 
01384       max_size += BTR_EXTERN_FIELD_REF_SIZE;
01385     }
01386 
01387     undo_page_len += 5 + max_size;
01388   }
01389 
01390   return(undo_page_len >= UNIV_PAGE_SIZE);
01391 }
01392 
01393 /****************************************************************/
01397 static
01398 ibool
01399 dict_index_too_big_for_tree(
01400 /*========================*/
01401   const dict_table_t* table,    
01402   const dict_index_t* new_index)  
01403 {
01404   ulint zip_size;
01405   ulint comp;
01406   ulint i;
01407   /* maximum possible storage size of a record */
01408   ulint rec_max_size;
01409   /* maximum allowed size of a record on a leaf page */
01410   ulint page_rec_max;
01411   /* maximum allowed size of a node pointer record */
01412   ulint page_ptr_max;
01413 
01414   comp = dict_table_is_comp(table);
01415   zip_size = dict_table_zip_size(table);
01416 
01417   if (zip_size && zip_size < UNIV_PAGE_SIZE) {
01418     /* On a compressed page, two records must fit in the
01419     uncompressed page modification log.  On compressed
01420     pages with zip_size == UNIV_PAGE_SIZE, this limit will
01421     never be reached. */
01422     ut_ad(comp);
01423     /* The maximum allowed record size is the size of
01424     an empty page, minus a byte for recoding the heap
01425     number in the page modification log.  The maximum
01426     allowed node pointer size is half that. */
01427     page_rec_max = page_zip_empty_size(new_index->n_fields,
01428                zip_size) - 1;
01429     page_ptr_max = page_rec_max / 2;
01430     /* On a compressed page, there is a two-byte entry in
01431     the dense page directory for every record.  But there
01432     is no record header. */
01433     rec_max_size = 2;
01434   } else {
01435     /* The maximum allowed record size is half a B-tree
01436     page.  No additional sparse page directory entry will
01437     be generated for the first few user records. */
01438     page_rec_max = page_get_free_space_of_empty(comp) / 2;
01439     page_ptr_max = page_rec_max;
01440     /* Each record has a header. */
01441     rec_max_size = comp
01442       ? REC_N_NEW_EXTRA_BYTES
01443       : REC_N_OLD_EXTRA_BYTES;
01444   }
01445 
01446   if (comp) {
01447     /* Include the "null" flags in the
01448     maximum possible record size. */
01449     rec_max_size += UT_BITS_IN_BYTES(new_index->n_nullable);
01450   } else {
01451     /* For each column, include a 2-byte offset and a
01452     "null" flag.  The 1-byte format is only used in short
01453     records that do not contain externally stored columns.
01454     Such records could never exceed the page limit, even
01455     when using the 2-byte format. */
01456     rec_max_size += 2 * new_index->n_fields;
01457   }
01458 
01459   /* Compute the maximum possible record size. */
01460   for (i = 0; i < new_index->n_fields; i++) {
01461     const dict_field_t* field
01462       = dict_index_get_nth_field(new_index, i);
01463     const dict_col_t* col
01464       = dict_field_get_col(field);
01465     ulint     field_max_size;
01466     ulint     field_ext_max_size;
01467 
01468     /* In dtuple_convert_big_rec(), variable-length columns
01469     that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
01470     may be chosen for external storage.
01471 
01472     Fixed-length columns, and all columns of secondary
01473     index records are always stored inline. */
01474 
01475     /* Determine the maximum length of the index field.
01476     The field_ext_max_size should be computed as the worst
01477     case in rec_get_converted_size_comp() for
01478     REC_STATUS_ORDINARY records. */
01479 
01480     field_max_size = dict_col_get_fixed_size(col, comp);
01481     if (field_max_size) {
01482       /* dict_index_add_col() should guarantee this */
01483       ut_ad(!field->prefix_len
01484             || field->fixed_len == field->prefix_len);
01485       /* Fixed lengths are not encoded
01486       in ROW_FORMAT=COMPACT. */
01487       field_ext_max_size = 0;
01488       goto add_field_size;
01489     }
01490 
01491     field_max_size = dict_col_get_max_size(col);
01492     field_ext_max_size = field_max_size < 256 ? 1 : 2;
01493 
01494     if (field->prefix_len) {
01495       if (field->prefix_len < field_max_size) {
01496         field_max_size = field->prefix_len;
01497       }
01498     } else if (field_max_size > BTR_EXTERN_FIELD_REF_SIZE * 2
01499          && dict_index_is_clust(new_index)) {
01500 
01501       /* In the worst case, we have a locally stored
01502       column of BTR_EXTERN_FIELD_REF_SIZE * 2 bytes.
01503       The length can be stored in one byte.  If the
01504       column were stored externally, the lengths in
01505       the clustered index page would be
01506       BTR_EXTERN_FIELD_REF_SIZE and 2. */
01507       field_max_size = BTR_EXTERN_FIELD_REF_SIZE * 2;
01508       field_ext_max_size = 1;
01509     }
01510 
01511     if (comp) {
01512       /* Add the extra size for ROW_FORMAT=COMPACT.
01513       For ROW_FORMAT=REDUNDANT, these bytes were
01514       added to rec_max_size before this loop. */
01515       rec_max_size += field_ext_max_size;
01516     }
01517 add_field_size:
01518     rec_max_size += field_max_size;
01519 
01520     /* Check the size limit on leaf pages. */
01521     if (UNIV_UNLIKELY(rec_max_size >= page_rec_max)) {
01522 
01523       return(TRUE);
01524     }
01525 
01526     /* Check the size limit on non-leaf pages.  Records
01527     stored in non-leaf B-tree pages consist of the unique
01528     columns of the record (the key columns of the B-tree)
01529     and a node pointer field.  When we have processed the
01530     unique columns, rec_max_size equals the size of the
01531     node pointer record minus the node pointer column. */
01532     if (i + 1 == dict_index_get_n_unique_in_tree(new_index)
01533         && rec_max_size + REC_NODE_PTR_SIZE >= page_ptr_max) {
01534 
01535       return(TRUE);
01536     }
01537   }
01538 
01539   return(FALSE);
01540 }
01541 
01542 /**********************************************************************/
01545 UNIV_INTERN
01546 ulint
01547 dict_index_add_to_cache(
01548 /*====================*/
01549   dict_table_t* table,  
01550   dict_index_t* index,  
01552   ulint   page_no,
01553   ibool   strict) 
01556 {
01557   dict_index_t* new_index;
01558   ulint   n_ord;
01559   ulint   i;
01560 
01561   ut_ad(index);
01562   ut_ad(mutex_own(&(dict_sys->mutex)));
01563   ut_ad(index->n_def == index->n_fields);
01564   ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
01565 
01566   ut_ad(mem_heap_validate(index->heap));
01567   ut_a(!dict_index_is_clust(index)
01568        || UT_LIST_GET_LEN(table->indexes) == 0);
01569 
01570   if (!dict_index_find_cols(table, index)) {
01571 
01572     dict_mem_index_free(index);
01573     return(DB_CORRUPTION);
01574   }
01575 
01576   /* Build the cache internal representation of the index,
01577   containing also the added system fields */
01578 
01579   if (dict_index_is_clust(index)) {
01580     new_index = dict_index_build_internal_clust(table, index);
01581   } else {
01582     new_index = dict_index_build_internal_non_clust(table, index);
01583   }
01584 
01585   /* Set the n_fields value in new_index to the actual defined
01586   number of fields in the cache internal representation */
01587 
01588   new_index->n_fields = new_index->n_def;
01589 
01590   if (strict && dict_index_too_big_for_tree(table, new_index)) {
01591 too_big:
01592     dict_mem_index_free(new_index);
01593     dict_mem_index_free(index);
01594     return(DB_TOO_BIG_RECORD);
01595   }
01596 
01597   if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
01598     n_ord = new_index->n_fields;
01599   } else {
01600     n_ord = new_index->n_uniq;
01601   }
01602 
01603   switch (dict_table_get_format(table)) {
01604   case DICT_TF_FORMAT_51:
01605     /* ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT store
01606     prefixes of externally stored columns locally within
01607     the record.  There are no special considerations for
01608     the undo log record size. */
01609     goto undo_size_ok;
01610 
01611   case DICT_TF_FORMAT_ZIP:
01612     /* In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED,
01613     column prefix indexes require that prefixes of
01614     externally stored columns are written to the undo log.
01615     This may make the undo log record bigger than the
01616     record on the B-tree page.  The maximum size of an
01617     undo log record is the page size.  That must be
01618     checked for below. */
01619     break;
01620 
01621 #if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
01622 # error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
01623 #endif
01624   }
01625 
01626   for (i = 0; i < n_ord; i++) {
01627     const dict_field_t* field
01628       = dict_index_get_nth_field(new_index, i);
01629     const dict_col_t* col
01630       = dict_field_get_col(field);
01631 
01632     /* In dtuple_convert_big_rec(), variable-length columns
01633     that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
01634     may be chosen for external storage.  If the column appears
01635     in an ordering column of an index, a longer prefix of
01636     REC_MAX_INDEX_COL_LEN will be copied to the undo log
01637     by trx_undo_page_report_modify() and
01638     trx_undo_page_fetch_ext().  It suffices to check the
01639     capacity of the undo log whenever new_index includes
01640     a column prefix on a column that may be stored externally. */
01641 
01642     if (field->prefix_len /* prefix index */
01643         && !col->ord_part /* not yet ordering column */
01644         && !dict_col_get_fixed_size(col, TRUE) /* variable-length */
01645         && dict_col_get_max_size(col)
01646         > BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
01647 
01648       if (dict_index_too_big_for_undo(table, new_index)) {
01649         /* An undo log record might not fit in
01650         a single page.  Refuse to create this index. */
01651 
01652         goto too_big;
01653       }
01654 
01655       break;
01656     }
01657   }
01658 
01659 undo_size_ok:
01660   /* Flag the ordering columns */
01661 
01662   for (i = 0; i < n_ord; i++) {
01663 
01664     dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
01665   }
01666 
01667   /* Add the new index as the last index for the table */
01668 
01669   UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
01670   new_index->table = table;
01671   new_index->table_name = table->name;
01672 
01673   new_index->search_info = btr_search_info_create(new_index->heap);
01674 
01675   new_index->stat_index_size = 1;
01676   new_index->stat_n_leaf_pages = 1;
01677 
01678   new_index->page = page_no;
01679   rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
01680            SYNC_INDEX_TREE);
01681 
01682   if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
01683 
01684     new_index->stat_n_diff_key_vals = static_cast<ib_int64_t *>(mem_heap_alloc(
01685       new_index->heap,
01686       (1 + dict_index_get_n_unique(new_index))
01687       * sizeof(ib_int64_t)));
01688     /* Give some sensible values to stat_n_... in case we do
01689     not calculate statistics quickly enough */
01690 
01691     for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
01692 
01693       new_index->stat_n_diff_key_vals[i] = 100;
01694     }
01695   }
01696 
01697   dict_sys->size += mem_heap_get_size(new_index->heap);
01698 
01699   dict_mem_index_free(index);
01700 
01701   return(DB_SUCCESS);
01702 }
01703 
01704 /**********************************************************************/
01706 UNIV_INTERN
01707 void
01708 dict_index_remove_from_cache(
01709 /*=========================*/
01710   dict_table_t* table,  
01711   dict_index_t* index)  
01712 {
01713   ulint   size;
01714   ulint   retries = 0;
01715   btr_search_t* info;
01716 
01717   ut_ad(table && index);
01718   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
01719   ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
01720   ut_ad(mutex_own(&(dict_sys->mutex)));
01721 
01722   /* We always create search info whether or not adaptive
01723   hash index is enabled or not. */
01724   info = index->search_info;
01725   ut_ad(info);
01726 
01727   /* We are not allowed to free the in-memory index struct
01728   dict_index_t until all entries in the adaptive hash index
01729   that point to any of the page belonging to his b-tree index
01730   are dropped. This is so because dropping of these entries
01731   require access to dict_index_t struct. To avoid such scenario
01732   We keep a count of number of such pages in the search_info and
01733   only free the dict_index_t struct when this count drops to
01734   zero. */
01735 
01736   for (;;) {
01737     ulint ref_count = btr_search_info_get_ref_count(info);
01738     if (ref_count == 0) {
01739       break;
01740     }
01741 
01742     /* Sleep for 10ms before trying again. */
01743     os_thread_sleep(10000);
01744     ++retries;
01745 
01746     if (retries % 500 == 0) {
01747       /* No luck after 5 seconds of wait. */
01748       fprintf(stderr, "InnoDB: Error: Waited for"
01749           " %lu secs for hash index"
01750           " ref_count (%lu) to drop"
01751           " to 0.\n"
01752           "index: \"%s\""
01753           " table: \"%s\"\n",
01754           retries/100,
01755           ref_count,
01756           index->name,
01757           table->name);
01758     }
01759 
01760     /* To avoid a hang here we commit suicide if the
01761     ref_count doesn't drop to zero in 600 seconds. */
01762     if (retries >= 60000) {
01763       ut_error;
01764     }
01765   }
01766 
01767   rw_lock_free(&index->lock);
01768 
01769   /* Remove the index from the list of indexes of the table */
01770   UT_LIST_REMOVE(indexes, table->indexes, index);
01771 
01772   size = mem_heap_get_size(index->heap);
01773 
01774   ut_ad(dict_sys->size >= size);
01775 
01776   dict_sys->size -= size;
01777 
01778   dict_mem_index_free(index);
01779 }
01780 
01781 /*******************************************************************/
01785 static
01786 ibool
01787 dict_index_find_cols(
01788 /*=================*/
01789   dict_table_t* table,  
01790   dict_index_t* index)  
01791 {
01792   ulint   i;
01793 
01794   ut_ad(table && index);
01795   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
01796   ut_ad(mutex_own(&(dict_sys->mutex)));
01797 
01798   for (i = 0; i < index->n_fields; i++) {
01799     ulint   j;
01800     dict_field_t* field = dict_index_get_nth_field(index, i);
01801 
01802     for (j = 0; j < table->n_cols; j++) {
01803       if (!strcmp(dict_table_get_col_name(table, j),
01804             field->name)) {
01805         field->col = dict_table_get_nth_col(table, j);
01806 
01807         goto found;
01808       }
01809     }
01810 
01811 #ifdef UNIV_DEBUG
01812     /* It is an error not to find a matching column. */
01813     fputs("InnoDB: Error: no matching column for ", stderr);
01814     ut_print_name(stderr, NULL, FALSE, field->name);
01815     fputs(" in ", stderr);
01816     dict_index_name_print(stderr, NULL, index);
01817     fputs("!\n", stderr);
01818 #endif /* UNIV_DEBUG */
01819     return(FALSE);
01820 
01821 found:
01822     ;
01823   }
01824 
01825   return(TRUE);
01826 }
01827 #endif /* !UNIV_HOTBACKUP */
01828 
01829 /*******************************************************************/
01831 UNIV_INTERN
01832 void
01833 dict_index_add_col(
01834 /*===============*/
01835   dict_index_t*   index,    
01836   const dict_table_t* table,    
01837   dict_col_t*   col,    
01838   ulint     prefix_len) 
01839 {
01840   dict_field_t* field;
01841   const char* col_name;
01842 
01843   col_name = dict_table_get_col_name(table, dict_col_get_no(col));
01844 
01845   dict_mem_index_add_field(index, col_name, prefix_len);
01846 
01847   field = dict_index_get_nth_field(index, index->n_def - 1);
01848 
01849   field->col = col;
01850   field->fixed_len = (unsigned int) dict_col_get_fixed_size(
01851     col, dict_table_is_comp(table));
01852 
01853   if (prefix_len && field->fixed_len > prefix_len) {
01854     field->fixed_len = (unsigned int) prefix_len;
01855   }
01856 
01857   /* Long fixed-length fields that need external storage are treated as
01858   variable-length fields, so that the extern flag can be embedded in
01859   the length word. */
01860 
01861   if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
01862     field->fixed_len = 0;
01863   }
01864 #if DICT_MAX_INDEX_COL_LEN != 1024
01865   /* The comparison limit above must be constant.  If it were
01866   changed, the disk format of some fixed-length columns would
01867   change, which would be a disaster. */
01868 # error "DICT_MAX_INDEX_COL_LEN != 1024"
01869 #endif
01870 
01871   if (!(col->prtype & DATA_NOT_NULL)) {
01872     index->n_nullable++;
01873   }
01874 }
01875 
01876 #ifndef UNIV_HOTBACKUP
01877 /*******************************************************************/
01879 static
01880 void
01881 dict_index_copy(
01882 /*============*/
01883   dict_index_t*   index1, 
01884   dict_index_t*   index2, 
01885   const dict_table_t* table,  
01886   ulint     start,  
01887   ulint     end)  
01888 {
01889   dict_field_t* field;
01890   ulint   i;
01891 
01892   /* Copy fields contained in index2 */
01893 
01894   for (i = start; i < end; i++) {
01895 
01896     field = dict_index_get_nth_field(index2, i);
01897     dict_index_add_col(index1, table, field->col,
01898            field->prefix_len);
01899   }
01900 }
01901 
01902 /*******************************************************************/
01904 UNIV_INTERN
01905 void
01906 dict_index_copy_types(
01907 /*==================*/
01908   dtuple_t*   tuple,    
01909   const dict_index_t* index,    
01910   ulint     n_fields) 
01912 {
01913   ulint   i;
01914 
01915   if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
01916     dtuple_set_types_binary(tuple, n_fields);
01917 
01918     return;
01919   }
01920 
01921   for (i = 0; i < n_fields; i++) {
01922     const dict_field_t* ifield;
01923     dtype_t*    dfield_type;
01924 
01925     ifield = dict_index_get_nth_field(index, i);
01926     dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
01927     dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
01928   }
01929 }
01930 
01931 /*******************************************************************/
01935 UNIV_INTERN
01936 void
01937 dict_table_copy_types(
01938 /*==================*/
01939   dtuple_t*   tuple,  
01940   const dict_table_t* table)  
01941 {
01942   ulint   i;
01943 
01944   for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
01945 
01946     dfield_t* dfield  = dtuple_get_nth_field(tuple, i);
01947     dtype_t*  dtype = dfield_get_type(dfield);
01948 
01949     dfield_set_null(dfield);
01950     dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
01951   }
01952 }
01953 
01954 /*******************************************************************/
01958 static
01959 dict_index_t*
01960 dict_index_build_internal_clust(
01961 /*============================*/
01962   const dict_table_t* table,  
01963   dict_index_t*   index)  
01965 {
01966   dict_index_t* new_index;
01967   dict_field_t* field;
01968   ulint   fixed_size;
01969   ulint   trx_id_pos;
01970   ulint   i;
01971   ibool*    indexed;
01972 
01973   ut_ad(table && index);
01974   ut_ad(dict_index_is_clust(index));
01975   ut_ad(mutex_own(&(dict_sys->mutex)));
01976   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
01977 
01978   /* Create a new index object with certainly enough fields */
01979   new_index = dict_mem_index_create(table->name,
01980             index->name, table->space,
01981             index->type,
01982             index->n_fields + table->n_cols);
01983 
01984   /* Copy other relevant data from the old index struct to the new
01985   struct: it inherits the values */
01986 
01987   new_index->n_user_defined_cols = index->n_fields;
01988 
01989   new_index->id = index->id;
01990 
01991   /* Copy the fields of index */
01992   dict_index_copy(new_index, index, table, 0, index->n_fields);
01993 
01994   if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
01995     /* No fixed number of fields determines an entry uniquely */
01996 
01997     new_index->n_uniq = REC_MAX_N_FIELDS;
01998 
01999   } else if (dict_index_is_unique(index)) {
02000     /* Only the fields defined so far are needed to identify
02001     the index entry uniquely */
02002 
02003     new_index->n_uniq = new_index->n_def;
02004   } else {
02005     /* Also the row id is needed to identify the entry */
02006     new_index->n_uniq = 1 + new_index->n_def;
02007   }
02008 
02009   new_index->trx_id_offset = 0;
02010 
02011   if (!dict_index_is_ibuf(index)) {
02012     /* Add system columns, trx id first */
02013 
02014     trx_id_pos = new_index->n_def;
02015 
02016 #if DATA_ROW_ID != 0
02017 # error "DATA_ROW_ID != 0"
02018 #endif
02019 #if DATA_TRX_ID != 1
02020 # error "DATA_TRX_ID != 1"
02021 #endif
02022 #if DATA_ROLL_PTR != 2
02023 # error "DATA_ROLL_PTR != 2"
02024 #endif
02025 
02026     if (!dict_index_is_unique(index)) {
02027       dict_index_add_col(new_index, table,
02028              dict_table_get_sys_col(
02029                table, DATA_ROW_ID),
02030              0);
02031       trx_id_pos++;
02032     }
02033 
02034     dict_index_add_col(new_index, table,
02035            dict_table_get_sys_col(table, DATA_TRX_ID),
02036            0);
02037 
02038     dict_index_add_col(new_index, table,
02039            dict_table_get_sys_col(table,
02040                 DATA_ROLL_PTR),
02041            0);
02042 
02043     for (i = 0; i < trx_id_pos; i++) {
02044 
02045       fixed_size = dict_col_get_fixed_size(
02046         dict_index_get_nth_col(new_index, i),
02047         dict_table_is_comp(table));
02048 
02049       if (fixed_size == 0) {
02050         new_index->trx_id_offset = 0;
02051 
02052         break;
02053       }
02054 
02055       if (dict_index_get_nth_field(new_index, i)->prefix_len
02056           > 0) {
02057         new_index->trx_id_offset = 0;
02058 
02059         break;
02060       }
02061 
02062       new_index->trx_id_offset += (unsigned int) fixed_size;
02063     }
02064 
02065   }
02066 
02067   /* Remember the table columns already contained in new_index */
02068         void *indexed_ptr= mem_zalloc(table->n_cols * sizeof *indexed);
02069   indexed = static_cast<unsigned long *>(indexed_ptr);
02070 
02071   /* Mark the table columns already contained in new_index */
02072   for (i = 0; i < new_index->n_def; i++) {
02073 
02074     field = dict_index_get_nth_field(new_index, i);
02075 
02076     /* If there is only a prefix of the column in the index
02077     field, do not mark the column as contained in the index */
02078 
02079     if (field->prefix_len == 0) {
02080 
02081       indexed[field->col->ind] = TRUE;
02082     }
02083   }
02084 
02085   /* Add to new_index non-system columns of table not yet included
02086   there */
02087   for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
02088 
02089     dict_col_t* col = dict_table_get_nth_col(table, i);
02090     ut_ad(col->mtype != DATA_SYS);
02091 
02092     if (!indexed[col->ind]) {
02093       dict_index_add_col(new_index, table, col, 0);
02094     }
02095   }
02096 
02097   mem_free(indexed);
02098 
02099   ut_ad(dict_index_is_ibuf(index)
02100         || (UT_LIST_GET_LEN(table->indexes) == 0));
02101 
02102   new_index->cached = TRUE;
02103 
02104   return(new_index);
02105 }
02106 
02107 /*******************************************************************/
02111 static
02112 dict_index_t*
02113 dict_index_build_internal_non_clust(
02114 /*================================*/
02115   const dict_table_t* table,  
02116   dict_index_t*   index)  
02118 {
02119   dict_field_t* field;
02120   dict_index_t* new_index;
02121   dict_index_t* clust_index;
02122   ulint   i;
02123   ibool*    indexed;
02124 
02125   ut_ad(table && index);
02126   ut_ad(!dict_index_is_clust(index));
02127   ut_ad(mutex_own(&(dict_sys->mutex)));
02128   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
02129 
02130   /* The clustered index should be the first in the list of indexes */
02131   clust_index = UT_LIST_GET_FIRST(table->indexes);
02132 
02133   ut_ad(clust_index);
02134   ut_ad(dict_index_is_clust(clust_index));
02135   ut_ad(!(clust_index->type & DICT_UNIVERSAL));
02136 
02137   /* Create a new index */
02138   new_index = dict_mem_index_create(
02139     table->name, index->name, index->space, index->type,
02140     index->n_fields + 1 + clust_index->n_uniq);
02141 
02142   /* Copy other relevant data from the old index
02143   struct to the new struct: it inherits the values */
02144 
02145   new_index->n_user_defined_cols = index->n_fields;
02146 
02147   new_index->id = index->id;
02148 
02149   /* Copy fields from index to new_index */
02150   dict_index_copy(new_index, index, table, 0, index->n_fields);
02151 
02152   /* Remember the table columns already contained in new_index */
02153         void *indexed_ptr= mem_zalloc(table->n_cols * sizeof *indexed);
02154   indexed = static_cast<unsigned long *>(indexed_ptr);
02155 
02156   /* Mark the table columns already contained in new_index */
02157   for (i = 0; i < new_index->n_def; i++) {
02158 
02159     field = dict_index_get_nth_field(new_index, i);
02160 
02161     /* If there is only a prefix of the column in the index
02162     field, do not mark the column as contained in the index */
02163 
02164     if (field->prefix_len == 0) {
02165 
02166       indexed[field->col->ind] = TRUE;
02167     }
02168   }
02169 
02170   /* Add to new_index the columns necessary to determine the clustered
02171   index entry uniquely */
02172 
02173   for (i = 0; i < clust_index->n_uniq; i++) {
02174 
02175     field = dict_index_get_nth_field(clust_index, i);
02176 
02177     if (!indexed[field->col->ind]) {
02178       dict_index_add_col(new_index, table, field->col,
02179              field->prefix_len);
02180     }
02181   }
02182 
02183   mem_free(indexed);
02184 
02185   if (dict_index_is_unique(index)) {
02186     new_index->n_uniq = index->n_fields;
02187   } else {
02188     new_index->n_uniq = new_index->n_def;
02189   }
02190 
02191   /* Set the n_fields value in new_index to the actual defined
02192   number of fields */
02193 
02194   new_index->n_fields = new_index->n_def;
02195 
02196   new_index->cached = TRUE;
02197 
02198   return(new_index);
02199 }
02200 
02201 /*====================== FOREIGN KEY PROCESSING ========================*/
02202 
02203 /*********************************************************************/
02206 UNIV_INTERN
02207 ibool
02208 dict_table_is_referenced_by_foreign_key(
02209 /*====================================*/
02210   const dict_table_t* table)  
02211 {
02212   return(UT_LIST_GET_LEN(table->referenced_list) > 0);
02213 }
02214 
02215 /*********************************************************************/
02220 UNIV_INTERN
02221 dict_foreign_t*
02222 dict_table_get_referenced_constraint(
02223 /*=================================*/
02224   dict_table_t* table,  
02225   dict_index_t* index)  
02226 {
02227   dict_foreign_t* foreign;
02228 
02229   ut_ad(index != NULL);
02230   ut_ad(table != NULL);
02231 
02232   for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
02233        foreign;
02234        foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
02235 
02236     if (foreign->referenced_index == index) {
02237 
02238       return(foreign);
02239     }
02240   }
02241 
02242   return(NULL);
02243 }
02244 
02245 /*********************************************************************/
02251 UNIV_INTERN
02252 dict_foreign_t*
02253 dict_table_get_foreign_constraint(
02254 /*==============================*/
02255   dict_table_t* table,  
02256   dict_index_t* index)  
02257 {
02258   dict_foreign_t* foreign;
02259 
02260   ut_ad(index != NULL);
02261   ut_ad(table != NULL);
02262 
02263   for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
02264        foreign;
02265        foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
02266 
02267     if (foreign->foreign_index == index
02268         || foreign->referenced_index == index) {
02269 
02270       return(foreign);
02271     }
02272   }
02273 
02274   return(NULL);
02275 }
02276 
02277 /*********************************************************************/
02279 static
02280 void
02281 dict_foreign_free(
02282 /*==============*/
02283   dict_foreign_t* foreign)  
02284 {
02285   mem_heap_free(foreign->heap);
02286 }
02287 
02288 /**********************************************************************/
02290 static
02291 void
02292 dict_foreign_remove_from_cache(
02293 /*===========================*/
02294   dict_foreign_t* foreign)  
02295 {
02296   ut_ad(mutex_own(&(dict_sys->mutex)));
02297   ut_a(foreign);
02298 
02299   if (foreign->referenced_table) {
02300     UT_LIST_REMOVE(referenced_list,
02301              foreign->referenced_table->referenced_list,
02302              foreign);
02303   }
02304 
02305   if (foreign->foreign_table) {
02306     UT_LIST_REMOVE(foreign_list,
02307              foreign->foreign_table->foreign_list,
02308              foreign);
02309   }
02310 
02311   dict_foreign_free(foreign);
02312 }
02313 
02314 /**********************************************************************/
02318 static
02319 dict_foreign_t*
02320 dict_foreign_find(
02321 /*==============*/
02322   dict_table_t* table,  
02323   const char* id) 
02324 {
02325   dict_foreign_t* foreign;
02326 
02327   ut_ad(mutex_own(&(dict_sys->mutex)));
02328 
02329   foreign = UT_LIST_GET_FIRST(table->foreign_list);
02330 
02331   while (foreign) {
02332     if (ut_strcmp(id, foreign->id) == 0) {
02333 
02334       return(foreign);
02335     }
02336 
02337     foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
02338   }
02339 
02340   foreign = UT_LIST_GET_FIRST(table->referenced_list);
02341 
02342   while (foreign) {
02343     if (ut_strcmp(id, foreign->id) == 0) {
02344 
02345       return(foreign);
02346     }
02347 
02348     foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
02349   }
02350 
02351   return(NULL);
02352 }
02353 
02354 /*********************************************************************/
02359 static
02360 dict_index_t*
02361 dict_foreign_find_index(
02362 /*====================*/
02363   dict_table_t* table,  
02364   const char**  columns,
02365   ulint   n_cols, 
02366   dict_index_t* types_idx, 
02368   ibool   check_charsets,
02371   ulint   check_null)
02374 {
02375   dict_index_t* index;
02376 
02377   index = dict_table_get_first_index(table);
02378 
02379   while (index != NULL) {
02380     /* Ignore matches that refer to the same instance
02381     or the index is to be dropped */
02382     if (index->to_be_dropped || types_idx == index) {
02383 
02384       goto next_rec;
02385 
02386     } else if (dict_index_get_n_fields(index) >= n_cols) {
02387       ulint   i;
02388 
02389       for (i = 0; i < n_cols; i++) {
02390         dict_field_t* field;
02391         const char* col_name;
02392 
02393         field = dict_index_get_nth_field(index, i);
02394 
02395         col_name = dict_table_get_col_name(
02396           table, dict_col_get_no(field->col));
02397 
02398         if (field->prefix_len != 0) {
02399           /* We do not accept column prefix
02400           indexes here */
02401 
02402           break;
02403         }
02404 
02405         if (0 != innobase_strcasecmp(columns[i],
02406                    col_name)) {
02407           break;
02408         }
02409 
02410         if (check_null
02411             && (field->col->prtype & DATA_NOT_NULL)) {
02412 
02413           return(NULL);
02414         }
02415 
02416         if (types_idx && !cmp_cols_are_equal(
02417               dict_index_get_nth_col(index, i),
02418               dict_index_get_nth_col(types_idx,
02419                    i),
02420               check_charsets)) {
02421 
02422           break;
02423         }
02424       }
02425 
02426       if (i == n_cols) {
02427         /* We found a matching index */
02428 
02429         return(index);
02430       }
02431     }
02432 
02433 next_rec:
02434     index = dict_table_get_next_index(index);
02435   }
02436 
02437   return(NULL);
02438 }
02439 
02440 /**********************************************************************/
02444 UNIV_INTERN
02445 dict_index_t*
02446 dict_foreign_find_equiv_index(
02447 /*==========================*/
02448   dict_foreign_t* foreign)
02449 {
02450   ut_a(foreign != NULL);
02451 
02452   /* Try to find an index which contains the columns as the
02453   first fields and in the right order, and the types are the
02454   same as in foreign->foreign_index */
02455 
02456   return(dict_foreign_find_index(
02457            foreign->foreign_table,
02458            foreign->foreign_col_names, foreign->n_fields,
02459            foreign->foreign_index, TRUE, /* check types */
02460            FALSE/* allow columns to be NULL */));
02461 }
02462 
02463 /**********************************************************************/
02467 UNIV_INTERN
02468 dict_index_t*
02469 dict_table_get_index_by_max_id(
02470 /*===========================*/
02471   dict_table_t* table,  
02472   const char* name, 
02473   const char**  columns,
02474   ulint   n_cols) 
02475 {
02476   dict_index_t* index;
02477   dict_index_t* found;
02478 
02479   found = NULL;
02480   index = dict_table_get_first_index(table);
02481 
02482   while (index != NULL) {
02483     if (ut_strcmp(index->name, name) == 0
02484         && dict_index_get_n_ordering_defined_by_user(index)
02485         == n_cols) {
02486 
02487       ulint   i;
02488 
02489       for (i = 0; i < n_cols; i++) {
02490         dict_field_t* field;
02491         const char* col_name;
02492 
02493         field = dict_index_get_nth_field(index, i);
02494 
02495         col_name = dict_table_get_col_name(
02496           table, dict_col_get_no(field->col));
02497 
02498         if (0 != innobase_strcasecmp(
02499               columns[i], col_name)) {
02500 
02501           break;
02502         }
02503       }
02504 
02505       if (i == n_cols) {
02506         /* We found a matching index, select
02507         the index with the higher id*/
02508 
02509         if (!found || index->id > found->id) {
02510 
02511           found = index;
02512         }
02513       }
02514     }
02515 
02516     index = dict_table_get_next_index(index);
02517   }
02518 
02519   return(found);
02520 }
02521 
02522 /**********************************************************************/
02524 static
02525 void
02526 dict_foreign_error_report_low(
02527 /*==========================*/
02528   FILE*   file, 
02529   const char* name) 
02530 {
02531   rewind(file);
02532   ut_print_timestamp(file);
02533   fprintf(file, " Error in foreign key constraint of table %s:\n",
02534     name);
02535 }
02536 
02537 /**********************************************************************/
02539 static
02540 void
02541 dict_foreign_error_report(
02542 /*======================*/
02543   FILE*   file, 
02544   dict_foreign_t* fk, 
02545   const char* msg)  
02546 {
02547   mutex_enter(&dict_foreign_err_mutex);
02548   dict_foreign_error_report_low(file, fk->foreign_table_name);
02549   fputs(msg, file);
02550   fputs(" Constraint:\n", file);
02551   dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
02552   putc('\n', file);
02553   if (fk->foreign_index) {
02554     fputs("The index in the foreign key in table is ", file);
02555     ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
02556     fputs("\n"
02557           "See " REFMAN "innodb-foreign-key-constraints.html\n"
02558           "for correct foreign key definition.\n",
02559           file);
02560   }
02561   mutex_exit(&dict_foreign_err_mutex);
02562 }
02563 
02564 /**********************************************************************/
02570 UNIV_INTERN
02571 ulint
02572 dict_foreign_add_to_cache(
02573 /*======================*/
02574   dict_foreign_t* foreign,  
02575   ibool   check_charsets) 
02577 {
02578   dict_table_t* for_table;
02579   dict_table_t* ref_table;
02580   dict_foreign_t* for_in_cache    = NULL;
02581   dict_index_t* index;
02582   ibool   added_to_referenced_list= FALSE;
02583   FILE*   ef      = dict_foreign_err_file;
02584 
02585   ut_ad(mutex_own(&(dict_sys->mutex)));
02586 
02587   for_table = dict_table_check_if_in_cache_low(
02588     foreign->foreign_table_name);
02589 
02590   ref_table = dict_table_check_if_in_cache_low(
02591     foreign->referenced_table_name);
02592   ut_a(for_table || ref_table);
02593 
02594   if (for_table) {
02595     for_in_cache = dict_foreign_find(for_table, foreign->id);
02596   }
02597 
02598   if (!for_in_cache && ref_table) {
02599     for_in_cache = dict_foreign_find(ref_table, foreign->id);
02600   }
02601 
02602   if (for_in_cache) {
02603     /* Free the foreign object */
02604     mem_heap_free(foreign->heap);
02605   } else {
02606     for_in_cache = foreign;
02607   }
02608 
02609   if (for_in_cache->referenced_table == NULL && ref_table) {
02610     index = dict_foreign_find_index(
02611       ref_table,
02612       for_in_cache->referenced_col_names,
02613       for_in_cache->n_fields, for_in_cache->foreign_index,
02614       check_charsets, FALSE);
02615 
02616     if (index == NULL) {
02617       dict_foreign_error_report(
02618         ef, for_in_cache,
02619         "there is no index in referenced table"
02620         " which would contain\n"
02621         "the columns as the first columns,"
02622         " or the data types in the\n"
02623         "referenced table do not match"
02624         " the ones in table.");
02625 
02626       if (for_in_cache == foreign) {
02627         mem_heap_free(foreign->heap);
02628       }
02629 
02630       return(DB_CANNOT_ADD_CONSTRAINT);
02631     }
02632 
02633     for_in_cache->referenced_table = ref_table;
02634     for_in_cache->referenced_index = index;
02635     UT_LIST_ADD_LAST(referenced_list,
02636          ref_table->referenced_list,
02637          for_in_cache);
02638     added_to_referenced_list = TRUE;
02639   }
02640 
02641   if (for_in_cache->foreign_table == NULL && for_table) {
02642     index = dict_foreign_find_index(
02643       for_table,
02644       for_in_cache->foreign_col_names,
02645       for_in_cache->n_fields,
02646       for_in_cache->referenced_index, check_charsets,
02647       for_in_cache->type
02648       & (DICT_FOREIGN_ON_DELETE_SET_NULL
02649          | DICT_FOREIGN_ON_UPDATE_SET_NULL));
02650 
02651     if (index == NULL) {
02652       dict_foreign_error_report(
02653         ef, for_in_cache,
02654         "there is no index in the table"
02655         " which would contain\n"
02656         "the columns as the first columns,"
02657         " or the data types in the\n"
02658         "table do not match"
02659         " the ones in the referenced table\n"
02660         "or one of the ON ... SET NULL columns"
02661         " is declared NOT NULL.");
02662 
02663       if (for_in_cache == foreign) {
02664         if (added_to_referenced_list) {
02665           UT_LIST_REMOVE(
02666             referenced_list,
02667             ref_table->referenced_list,
02668             for_in_cache);
02669         }
02670 
02671         mem_heap_free(foreign->heap);
02672       }
02673 
02674       return(DB_CANNOT_ADD_CONSTRAINT);
02675     }
02676 
02677     for_in_cache->foreign_table = for_table;
02678     for_in_cache->foreign_index = index;
02679     UT_LIST_ADD_LAST(foreign_list,
02680          for_table->foreign_list,
02681          for_in_cache);
02682   }
02683 
02684   return(DB_SUCCESS);
02685 }
02686 
02687 /*********************************************************************/
02692 static
02693 const char*
02694 dict_scan_to(
02695 /*=========*/
02696   const char* ptr,  
02697   const char* string) 
02698 {
02699   char  quote = '\0';
02700 
02701   for (; *ptr; ptr++) {
02702     if (*ptr == quote) {
02703       /* Closing quote character: do not look for
02704       starting quote or the keyword. */
02705       quote = '\0';
02706     } else if (quote) {
02707       /* Within quotes: do nothing. */
02708     } else if (*ptr == '`' || *ptr == '"') {
02709       /* Starting quote: remember the quote character. */
02710       quote = *ptr;
02711     } else {
02712       /* Outside quotes: look for the keyword. */
02713       ulint i;
02714       for (i = 0; string[i]; i++) {
02715         if (toupper((int)(unsigned char)(ptr[i]))
02716             != toupper((int)(unsigned char)
02717                  (string[i]))) {
02718           goto nomatch;
02719         }
02720       }
02721       break;
02722 nomatch:
02723       ;
02724     }
02725   }
02726 
02727   return(ptr);
02728 }
02729 
02730 /*********************************************************************/
02734 static
02735 const char*
02736 dict_accept(
02737 /*========*/
02738   const void* cs,
02739   const char* ptr,  
02740   const char* string, 
02742   ibool*    success)
02743 {
02744   const char* old_ptr = ptr;
02745   const char* old_ptr2;
02746 
02747   *success = FALSE;
02748 
02749   while (innobase_isspace(cs, *ptr)) {
02750     ptr++;
02751   }
02752 
02753   old_ptr2 = ptr;
02754 
02755   ptr = dict_scan_to(ptr, string);
02756 
02757   if (*ptr == '\0' || old_ptr2 != ptr) {
02758     return(old_ptr);
02759   }
02760 
02761   *success = TRUE;
02762 
02763   return(ptr + ut_strlen(string));
02764 }
02765 
02766 /*********************************************************************/
02770 static
02771 const char*
02772 dict_scan_id(
02773 /*=========*/
02774   const void* cs,
02775   const char* ptr,  
02776   mem_heap_t* heap, 
02779   const char**  id, 
02781   ibool   table_id,
02783   ibool   accept_also_dot)
02787 {
02788   char    quote = '\0';
02789   ulint   len = 0;
02790   const char* s;
02791   char*   str;
02792   char*   dst;
02793 
02794   *id = NULL;
02795 
02796   while (innobase_isspace(cs, *ptr)) {
02797     ptr++;
02798   }
02799 
02800   if (*ptr == '\0') {
02801 
02802     return(ptr);
02803   }
02804 
02805   if (*ptr == '`' || *ptr == '"') {
02806     quote = *ptr++;
02807   }
02808 
02809   s = ptr;
02810 
02811   if (quote) {
02812     for (;;) {
02813       if (!*ptr) {
02814         /* Syntax error */
02815         return(ptr);
02816       }
02817       if (*ptr == quote) {
02818         ptr++;
02819         if (*ptr != quote) {
02820           break;
02821         }
02822       }
02823       ptr++;
02824       len++;
02825     }
02826   } else {
02827     while (!innobase_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
02828            && (accept_also_dot || *ptr != '.')
02829            && *ptr != ',' && *ptr != '\0') {
02830 
02831       ptr++;
02832     }
02833 
02834     len = ptr - s;
02835   }
02836 
02837   if (UNIV_UNLIKELY(!heap)) {
02838     /* no heap given: id will point to source string */
02839     *id = s;
02840     return(ptr);
02841   }
02842 
02843   if (quote) {
02844     char* d;
02845     str = d = static_cast<char *>(mem_heap_alloc(heap, len + 1));
02846     while (len--) {
02847       if ((*d++ = *s++) == quote) {
02848         s++;
02849       }
02850     }
02851     *d++ = 0;
02852     len = d - str;
02853     ut_ad(*s == quote);
02854     ut_ad(s + 1 == ptr);
02855   } else {
02856     str = mem_heap_strdupl(heap, s, len);
02857   }
02858 
02859   if (!table_id) {
02860 convert_id:
02861     /* Convert the identifier from connection character set
02862     to UTF-8. */
02863     len = 3 * len + 1;
02864     *id = dst = static_cast<char *>(mem_heap_alloc(heap, len));
02865 
02866     innobase_convert_from_id(cs, dst, str, len);
02867   } else if (!strncmp(str, srv_mysql50_table_name_prefix.c_str(),
02868           srv_mysql50_table_name_prefix.size())) {
02869     /* This is a pre-5.1 table name
02870     containing chars other than [A-Za-z0-9].
02871     Discard the prefix and use raw UTF-8 encoding. */
02872     str += srv_mysql50_table_name_prefix.size();
02873     len -= srv_mysql50_table_name_prefix.size();
02874     goto convert_id;
02875   } else {
02876     /* Encode using filename-safe characters. */
02877     len = 5 * len + 1;
02878     *id = dst = static_cast<char *>(mem_heap_alloc(heap, len));
02879 
02880     innobase_convert_from_table_id(cs, dst, str, len);
02881   }
02882 
02883   return(ptr);
02884 }
02885 
02886 /*********************************************************************/
02889 static
02890 const char*
02891 dict_scan_col(
02892 /*==========*/
02893   const void* cs, 
02894   const char*   ptr,  
02895   ibool*      success,
02896   dict_table_t*   table,  
02897   const dict_col_t**  column, 
02898   mem_heap_t*   heap, 
02899   const char**    name) 
02901 {
02902   ulint   i;
02903 
02904   *success = FALSE;
02905 
02906   ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
02907 
02908   if (*name == NULL) {
02909 
02910     return(ptr);  /* Syntax error */
02911   }
02912 
02913   if (table == NULL) {
02914     *success = TRUE;
02915     *column = NULL;
02916   } else {
02917     for (i = 0; i < dict_table_get_n_cols(table); i++) {
02918 
02919       const char* col_name = dict_table_get_col_name(
02920         table, i);
02921 
02922       if (0 == innobase_strcasecmp(col_name, *name)) {
02923         /* Found */
02924 
02925         *success = TRUE;
02926         *column = dict_table_get_nth_col(table, i);
02927         strcpy((char*) *name, col_name);
02928 
02929         break;
02930       }
02931     }
02932   }
02933 
02934   return(ptr);
02935 }
02936 
02937 /*********************************************************************/
02940 static
02941 const char*
02942 dict_scan_table_name(
02943 /*=================*/
02944   const void* cs,
02945   const char* ptr,  
02946   dict_table_t**  table,  
02947   const char* name, 
02948   ibool*    success,
02949   mem_heap_t* heap, 
02950   const char**  ref_name)
02952 {
02953   const char* database_name = NULL;
02954   ulint   database_name_len = 0;
02955   const char* table_name  = NULL;
02956   ulint   table_name_len;
02957   const char* scan_name;
02958   char*   ref;
02959 
02960   *success = FALSE;
02961   *table = NULL;
02962 
02963   ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
02964 
02965   if (scan_name == NULL) {
02966 
02967     return(ptr);  /* Syntax error */
02968   }
02969 
02970   if (*ptr == '.') {
02971     /* We scanned the database name; scan also the table name */
02972 
02973     ptr++;
02974 
02975     database_name = scan_name;
02976     database_name_len = strlen(database_name);
02977 
02978     ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
02979 
02980     if (table_name == NULL) {
02981 
02982       return(ptr);  /* Syntax error */
02983     }
02984   } else {
02985     /* To be able to read table dumps made with InnoDB-4.0.17 or
02986     earlier, we must allow the dot separator between the database
02987     name and the table name also to appear within a quoted
02988     identifier! InnoDB used to print a constraint as:
02989     ... REFERENCES `databasename.tablename` ...
02990     starting from 4.0.18 it is
02991     ... REFERENCES `databasename`.`tablename` ... */
02992     const char* s;
02993 
02994     for (s = scan_name; *s; s++) {
02995       if (*s == '.') {
02996         database_name = scan_name;
02997         database_name_len = s - scan_name;
02998         scan_name = ++s;
02999         break;/* to do: multiple dots? */
03000       }
03001     }
03002 
03003     table_name = scan_name;
03004   }
03005 
03006   if (database_name == NULL) {
03007     /* Use the database name of the foreign key table */
03008 
03009     database_name = name;
03010     database_name_len = dict_get_db_name_len(name);
03011   }
03012 
03013   table_name_len = strlen(table_name);
03014 
03015   /* Copy database_name, '/', table_name, '\0' */
03016   ref = static_cast<char *>(mem_heap_alloc(heap, database_name_len + table_name_len + 2));
03017   memcpy(ref, database_name, database_name_len);
03018   ref[database_name_len] = '/';
03019   memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
03020 #ifndef __WIN__
03021   if (srv_lower_case_table_names) {
03022 #endif /* !__WIN__ */
03023     /* The table name is always put to lower case on Windows. */
03024     innobase_casedn_str(ref);
03025 #ifndef __WIN__
03026   }
03027 #endif /* !__WIN__ */
03028 
03029   *success = TRUE;
03030   *ref_name = ref;
03031   *table = dict_table_get_low(ref);
03032 
03033   return(ptr);
03034 }
03035 
03036 /*********************************************************************/
03039 static
03040 const char*
03041 dict_skip_word(
03042 /*===========*/
03043   const void* cs,
03044   const char* ptr,  
03045   ibool*    success)
03047 {
03048   const char* start;
03049 
03050   *success = FALSE;
03051 
03052   ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
03053 
03054   if (start) {
03055     *success = TRUE;
03056   }
03057 
03058   return(ptr);
03059 }
03060 
03061 /*********************************************************************/
03069 static
03070 char*
03071 dict_strip_comments(
03072 /*================*/
03073   const char* sql_string, 
03074   size_t    sql_length) 
03075 {
03076   char*   str;
03077   const char* sptr;
03078   const char* eptr  = sql_string + sql_length;
03079   char*   ptr;
03080   /* unclosed quote character (0 if none) */
03081   char    quote = 0;
03082 
03083   str = static_cast<char *>(mem_alloc(sql_length + 1));
03084 
03085   sptr = sql_string;
03086   ptr = str;
03087 
03088   for (;;) {
03089 scan_more:
03090     if (sptr >= eptr || *sptr == '\0') {
03091 end_of_string:
03092       *ptr = '\0';
03093 
03094       ut_a(ptr <= str + sql_length);
03095 
03096       return(str);
03097     }
03098 
03099     if (*sptr == quote) {
03100       /* Closing quote character: do not look for
03101       starting quote or comments. */
03102       quote = 0;
03103     } else if (quote) {
03104       /* Within quotes: do not look for
03105       starting quotes or comments. */
03106     } else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
03107       /* Starting quote: remember the quote character. */
03108       quote = *sptr;
03109     } else if (*sptr == '#'
03110          || (sptr[0] == '-' && sptr[1] == '-'
03111              && sptr[2] == ' ')) {
03112       for (;;) {
03113         if (++sptr >= eptr) {
03114           goto end_of_string;
03115         }
03116 
03117         /* In Unix a newline is 0x0A while in Windows
03118         it is 0x0D followed by 0x0A */
03119 
03120         switch (*sptr) {
03121         case (char) 0X0A:
03122         case (char) 0x0D:
03123         case '\0':
03124           goto scan_more;
03125         }
03126       }
03127     } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
03128       sptr += 2;
03129       for (;;) {
03130         if (sptr >= eptr) {
03131           goto end_of_string;
03132         }
03133 
03134         switch (*sptr) {
03135         case '\0':
03136           goto scan_more;
03137         case '*':
03138           if (sptr[1] == '/') {
03139             sptr += 2;
03140             goto scan_more;
03141           }
03142         }
03143 
03144         sptr++;
03145       }
03146     }
03147 
03148     *ptr = *sptr;
03149 
03150     ptr++;
03151     sptr++;
03152   }
03153 }
03154 
03155 /*********************************************************************/
03160 static
03161 ulint
03162 dict_table_get_highest_foreign_id(
03163 /*==============================*/
03164   dict_table_t* table)  
03165 {
03166   dict_foreign_t* foreign;
03167   char*   endp;
03168   ulint   biggest_id  = 0;
03169   ulint   id;
03170   ulint   len;
03171 
03172   ut_a(table);
03173 
03174   len = ut_strlen(table->name);
03175   foreign = UT_LIST_GET_FIRST(table->foreign_list);
03176 
03177   while (foreign) {
03178     if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
03179         && 0 == ut_memcmp(foreign->id, table->name, len)
03180         && 0 == ut_memcmp(foreign->id + len,
03181               dict_ibfk, (sizeof dict_ibfk) - 1)
03182         && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
03183       /* It is of the >= 4.0.18 format */
03184 
03185       id = strtoul(foreign->id + len
03186              + ((sizeof dict_ibfk) - 1),
03187              &endp, 10);
03188       if (*endp == '\0') {
03189         ut_a(id != biggest_id);
03190 
03191         if (id > biggest_id) {
03192           biggest_id = id;
03193         }
03194       }
03195     }
03196 
03197     foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
03198   }
03199 
03200   return(biggest_id);
03201 }
03202 
03203 /*********************************************************************/
03205 static
03206 void
03207 dict_foreign_report_syntax_err(
03208 /*===========================*/
03209   const char* name,   
03210   const char* start_of_latest_foreign,
03213   const char* ptr)    
03214 {
03215   FILE* ef = dict_foreign_err_file;
03216 
03217   mutex_enter(&dict_foreign_err_mutex);
03218   dict_foreign_error_report_low(ef, name);
03219   fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
03220     start_of_latest_foreign, ptr);
03221   mutex_exit(&dict_foreign_err_mutex);
03222 }
03223 
03224 /*********************************************************************/
03231 static
03232 ulint
03233 dict_create_foreign_constraints_low(
03234 /*================================*/
03235   trx_t*    trx,  
03236   mem_heap_t* heap, 
03237   const void* cs,
03238   const char* sql_string,
03245   const char* name, 
03247   ibool   reject_fks)
03251 {
03252   dict_table_t* table;
03253   dict_table_t* referenced_table;
03254   dict_table_t* table_to_alter;
03255   ulint   highest_id_so_far = 0;
03256   dict_index_t* index;
03257   dict_foreign_t* foreign;
03258   const char* ptr     = sql_string;
03259   const char* start_of_latest_foreign = sql_string;
03260   FILE*   ef      = dict_foreign_err_file;
03261   const char* constraint_name;
03262   ibool   success;
03263   ulint   error;
03264   const char* ptr1;
03265   const char* ptr2;
03266   ulint   i;
03267   ulint   j;
03268   ibool   is_on_delete;
03269   ulint   n_on_deletes;
03270   ulint   n_on_updates;
03271   const dict_col_t*columns[500];
03272   const char* column_names[500];
03273   const char* referenced_table_name;
03274 
03275   ut_ad(mutex_own(&(dict_sys->mutex)));
03276 
03277   table = dict_table_get_low(name);
03278 
03279   if (table == NULL) {
03280     mutex_enter(&dict_foreign_err_mutex);
03281     dict_foreign_error_report_low(ef, name);
03282     fprintf(ef,
03283       "Cannot find the table in the internal"
03284       " data dictionary of InnoDB.\n"
03285       "Create table statement:\n%s\n", sql_string);
03286     mutex_exit(&dict_foreign_err_mutex);
03287 
03288     return(DB_ERROR);
03289   }
03290 
03291   /* First check if we are actually doing an ALTER TABLE, and in that
03292   case look for the table being altered */
03293 
03294   ptr = dict_accept(cs, ptr, "ALTER", &success);
03295 
03296   if (!success) {
03297 
03298     goto loop;
03299   }
03300 
03301   ptr = dict_accept(cs, ptr, "TABLE", &success);
03302 
03303   if (!success) {
03304 
03305     goto loop;
03306   }
03307 
03308   /* We are doing an ALTER TABLE: scan the table name we are altering */
03309 
03310   ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
03311            &success, heap, &referenced_table_name);
03312   if (!success) {
03313     fprintf(stderr,
03314       "InnoDB: Error: could not find"
03315       " the table being ALTERED in:\n%s\n",
03316       sql_string);
03317 
03318     return(DB_ERROR);
03319   }
03320 
03321   /* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
03322   format databasename/tablename_ibfk_[number], where [number] is local
03323   to the table; look for the highest [number] for table_to_alter, so
03324   that we can assign to new constraints higher numbers. */
03325 
03326   /* If we are altering a temporary table, the table name after ALTER
03327   TABLE does not correspond to the internal table name, and
03328   table_to_alter is NULL. TODO: should we fix this somehow? */
03329 
03330   if (table_to_alter == NULL) {
03331     highest_id_so_far = 0;
03332   } else {
03333     highest_id_so_far = dict_table_get_highest_foreign_id(
03334       table_to_alter);
03335   }
03336 
03337   /* Scan for foreign key declarations in a loop */
03338 loop:
03339   /* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
03340 
03341   ptr1 = dict_scan_to(ptr, "CONSTRAINT");
03342   ptr2 = dict_scan_to(ptr, "FOREIGN");
03343 
03344   constraint_name = NULL;
03345 
03346   if (ptr1 < ptr2) {
03347     /* The user may have specified a constraint name. Pick it so
03348     that we can store 'databasename/constraintname' as the id of
03349     of the constraint to system tables. */
03350     ptr = ptr1;
03351 
03352     ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
03353 
03354     ut_a(success);
03355 
03356     if (!innobase_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
03357       goto loop;
03358     }
03359 
03360     while (innobase_isspace(cs, *ptr)) {
03361       ptr++;
03362     }
03363 
03364     /* read constraint name unless got "CONSTRAINT FOREIGN" */
03365     if (ptr != ptr2) {
03366       ptr = dict_scan_id(cs, ptr, heap,
03367              &constraint_name, FALSE, FALSE);
03368     }
03369   } else {
03370     ptr = ptr2;
03371   }
03372 
03373   if (*ptr == '\0') {
03374     /* The proper way to reject foreign keys for temporary
03375     tables would be to split the lexing and syntactical
03376     analysis of foreign key clauses from the actual adding
03377     of them, so that ha_innodb.cc could first parse the SQL
03378     command, determine if there are any foreign keys, and
03379     if so, immediately reject the command if the table is a
03380     temporary one. For now, this kludge will work. */
03381     if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
03382 
03383       return(DB_CANNOT_ADD_CONSTRAINT);
03384     }
03385 
03386     /**********************************************************/
03387     /* The following call adds the foreign key constraints
03388     to the data dictionary system tables on disk */
03389 
03390     error = dict_create_add_foreigns_to_dictionary(
03391       highest_id_so_far, table, trx);
03392     return(error);
03393   }
03394 
03395   start_of_latest_foreign = ptr;
03396 
03397   ptr = dict_accept(cs, ptr, "FOREIGN", &success);
03398 
03399   if (!success) {
03400     goto loop;
03401   }
03402 
03403   if (!innobase_isspace(cs, *ptr)) {
03404     goto loop;
03405   }
03406 
03407   ptr = dict_accept(cs, ptr, "KEY", &success);
03408 
03409   if (!success) {
03410     goto loop;
03411   }
03412 
03413   ptr = dict_accept(cs, ptr, "(", &success);
03414 
03415   if (!success) {
03416     /* MySQL allows also an index id before the '('; we
03417     skip it */
03418     ptr = dict_skip_word(cs, ptr, &success);
03419 
03420     if (!success) {
03421       dict_foreign_report_syntax_err(
03422         name, start_of_latest_foreign, ptr);
03423 
03424       return(DB_CANNOT_ADD_CONSTRAINT);
03425     }
03426 
03427     ptr = dict_accept(cs, ptr, "(", &success);
03428 
03429     if (!success) {
03430       /* We do not flag a syntax error here because in an
03431       ALTER TABLE we may also have DROP FOREIGN KEY abc */
03432 
03433       goto loop;
03434     }
03435   }
03436 
03437   i = 0;
03438 
03439   /* Scan the columns in the first list */
03440 col_loop1:
03441   ut_a(i < (sizeof column_names) / sizeof *column_names);
03442   ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
03443           heap, column_names + i);
03444   if (!success) {
03445     mutex_enter(&dict_foreign_err_mutex);
03446     dict_foreign_error_report_low(ef, name);
03447     fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
03448       start_of_latest_foreign, ptr);
03449     mutex_exit(&dict_foreign_err_mutex);
03450 
03451     return(DB_CANNOT_ADD_CONSTRAINT);
03452   }
03453 
03454   i++;
03455 
03456   ptr = dict_accept(cs, ptr, ",", &success);
03457 
03458   if (success) {
03459     goto col_loop1;
03460   }
03461 
03462   ptr = dict_accept(cs, ptr, ")", &success);
03463 
03464   if (!success) {
03465     dict_foreign_report_syntax_err(
03466       name, start_of_latest_foreign, ptr);
03467     return(DB_CANNOT_ADD_CONSTRAINT);
03468   }
03469 
03470   /* Try to find an index which contains the columns
03471   as the first fields and in the right order */
03472 
03473   index = dict_foreign_find_index(table, column_names, i,
03474           NULL, TRUE, FALSE);
03475 
03476   if (!index) {
03477     mutex_enter(&dict_foreign_err_mutex);
03478     dict_foreign_error_report_low(ef, name);
03479     fputs("There is no index in table ", ef);
03480     ut_print_name(ef, NULL, TRUE, name);
03481     fprintf(ef, " where the columns appear\n"
03482       "as the first columns. Constraint:\n%s\n"
03483       "See " REFMAN "innodb-foreign-key-constraints.html\n"
03484       "for correct foreign key definition.\n",
03485       start_of_latest_foreign);
03486     mutex_exit(&dict_foreign_err_mutex);
03487 
03488     return(DB_CHILD_NO_INDEX);
03489   }
03490   ptr = dict_accept(cs, ptr, "REFERENCES", &success);
03491 
03492   if (!success || !innobase_isspace(cs, *ptr)) {
03493     dict_foreign_report_syntax_err(
03494       name, start_of_latest_foreign, ptr);
03495     return(DB_CANNOT_ADD_CONSTRAINT);
03496   }
03497 
03498   /* Let us create a constraint struct */
03499 
03500   foreign = dict_mem_foreign_create();
03501 
03502   if (constraint_name) {
03503     ulint db_len;
03504 
03505     /* Catenate 'databasename/' to the constraint name specified
03506     by the user: we conceive the constraint as belonging to the
03507     same MySQL 'database' as the table itself. We store the name
03508     to foreign->id. */
03509 
03510     db_len = dict_get_db_name_len(table->name);
03511 
03512     foreign->id = static_cast<char*>(mem_heap_alloc(
03513       foreign->heap, db_len + strlen(constraint_name) + 2));
03514 
03515     ut_memcpy(foreign->id, table->name, db_len);
03516     foreign->id[db_len] = '/';
03517     strcpy(foreign->id + db_len + 1, constraint_name);
03518   }
03519 
03520   foreign->foreign_table = table;
03521   foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
03522                   table->name);
03523   foreign->foreign_index = index;
03524   foreign->n_fields = (unsigned int) i;
03525   foreign->foreign_col_names = static_cast<const char **>(mem_heap_alloc(foreign->heap,
03526                 i * sizeof(void*)));
03527   for (i = 0; i < foreign->n_fields; i++) {
03528     foreign->foreign_col_names[i] = mem_heap_strdup(
03529       foreign->heap,
03530       dict_table_get_col_name(table,
03531             dict_col_get_no(columns[i])));
03532   }
03533 
03534   ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
03535            &success, heap, &referenced_table_name);
03536 
03537   /* Note that referenced_table can be NULL if the user has suppressed
03538   checking of foreign key constraints! */
03539 
03540   if (!success || (!referenced_table && trx->check_foreigns)) {
03541     dict_foreign_free(foreign);
03542 
03543     mutex_enter(&dict_foreign_err_mutex);
03544     dict_foreign_error_report_low(ef, name);
03545     fprintf(ef, "%s:\nCannot resolve table name close to:\n"
03546       "%s\n",
03547       start_of_latest_foreign, ptr);
03548     mutex_exit(&dict_foreign_err_mutex);
03549 
03550     return(DB_CANNOT_ADD_CONSTRAINT);
03551   }
03552 
03553   ptr = dict_accept(cs, ptr, "(", &success);
03554 
03555   if (!success) {
03556     dict_foreign_free(foreign);
03557     dict_foreign_report_syntax_err(name, start_of_latest_foreign,
03558                  ptr);
03559     return(DB_CANNOT_ADD_CONSTRAINT);
03560   }
03561 
03562   /* Scan the columns in the second list */
03563   i = 0;
03564 
03565 col_loop2:
03566   ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
03567           heap, column_names + i);
03568   i++;
03569 
03570   if (!success) {
03571     dict_foreign_free(foreign);
03572 
03573     mutex_enter(&dict_foreign_err_mutex);
03574     dict_foreign_error_report_low(ef, name);
03575     fprintf(ef, "%s:\nCannot resolve column name close to:\n"
03576       "%s\n",
03577       start_of_latest_foreign, ptr);
03578     mutex_exit(&dict_foreign_err_mutex);
03579 
03580     return(DB_CANNOT_ADD_CONSTRAINT);
03581   }
03582 
03583   ptr = dict_accept(cs, ptr, ",", &success);
03584 
03585   if (success) {
03586     goto col_loop2;
03587   }
03588 
03589   ptr = dict_accept(cs, ptr, ")", &success);
03590 
03591   if (!success || foreign->n_fields != i) {
03592     dict_foreign_free(foreign);
03593 
03594     dict_foreign_report_syntax_err(name, start_of_latest_foreign,
03595                  ptr);
03596     return(DB_CANNOT_ADD_CONSTRAINT);
03597   }
03598 
03599   n_on_deletes = 0;
03600   n_on_updates = 0;
03601 
03602 scan_on_conditions:
03603   /* Loop here as long as we can find ON ... conditions */
03604 
03605   ptr = dict_accept(cs, ptr, "ON", &success);
03606 
03607   if (!success) {
03608 
03609     goto try_find_index;
03610   }
03611 
03612   ptr = dict_accept(cs, ptr, "DELETE", &success);
03613 
03614   if (!success) {
03615     ptr = dict_accept(cs, ptr, "UPDATE", &success);
03616 
03617     if (!success) {
03618       dict_foreign_free(foreign);
03619 
03620       dict_foreign_report_syntax_err(
03621         name, start_of_latest_foreign, ptr);
03622       return(DB_CANNOT_ADD_CONSTRAINT);
03623     }
03624 
03625     is_on_delete = FALSE;
03626     n_on_updates++;
03627   } else {
03628     is_on_delete = TRUE;
03629     n_on_deletes++;
03630   }
03631 
03632   ptr = dict_accept(cs, ptr, "RESTRICT", &success);
03633 
03634   if (success) {
03635     goto scan_on_conditions;
03636   }
03637 
03638   ptr = dict_accept(cs, ptr, "CASCADE", &success);
03639 
03640   if (success) {
03641     if (is_on_delete) {
03642       foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
03643     } else {
03644       foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
03645     }
03646 
03647     goto scan_on_conditions;
03648   }
03649 
03650   ptr = dict_accept(cs, ptr, "NO", &success);
03651 
03652   if (success) {
03653     ptr = dict_accept(cs, ptr, "ACTION", &success);
03654 
03655     if (!success) {
03656       dict_foreign_free(foreign);
03657       dict_foreign_report_syntax_err(
03658         name, start_of_latest_foreign, ptr);
03659 
03660       return(DB_CANNOT_ADD_CONSTRAINT);
03661     }
03662 
03663     if (is_on_delete) {
03664       foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
03665     } else {
03666       foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
03667     }
03668 
03669     goto scan_on_conditions;
03670   }
03671 
03672   ptr = dict_accept(cs, ptr, "SET", &success);
03673 
03674   if (!success) {
03675     dict_foreign_free(foreign);
03676     dict_foreign_report_syntax_err(name, start_of_latest_foreign,
03677                  ptr);
03678     return(DB_CANNOT_ADD_CONSTRAINT);
03679   }
03680 
03681   ptr = dict_accept(cs, ptr, "NULL", &success);
03682 
03683   if (!success) {
03684     dict_foreign_free(foreign);
03685     dict_foreign_report_syntax_err(name, start_of_latest_foreign,
03686                  ptr);
03687     return(DB_CANNOT_ADD_CONSTRAINT);
03688   }
03689 
03690   for (j = 0; j < foreign->n_fields; j++) {
03691     if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
03692         & DATA_NOT_NULL) {
03693 
03694       /* It is not sensible to define SET NULL
03695       if the column is not allowed to be NULL! */
03696 
03697       dict_foreign_free(foreign);
03698 
03699       mutex_enter(&dict_foreign_err_mutex);
03700       dict_foreign_error_report_low(ef, name);
03701       fprintf(ef, "%s:\n"
03702         "You have defined a SET NULL condition"
03703         " though some of the\n"
03704         "columns are defined as NOT NULL.\n",
03705         start_of_latest_foreign);
03706       mutex_exit(&dict_foreign_err_mutex);
03707 
03708       return(DB_CANNOT_ADD_CONSTRAINT);
03709     }
03710   }
03711 
03712   if (is_on_delete) {
03713     foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
03714   } else {
03715     foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
03716   }
03717 
03718   goto scan_on_conditions;
03719 
03720 try_find_index:
03721   if (n_on_deletes > 1 || n_on_updates > 1) {
03722     /* It is an error to define more than 1 action */
03723 
03724     dict_foreign_free(foreign);
03725 
03726     mutex_enter(&dict_foreign_err_mutex);
03727     dict_foreign_error_report_low(ef, name);
03728     fprintf(ef, "%s:\n"
03729       "You have twice an ON DELETE clause"
03730       " or twice an ON UPDATE clause.\n",
03731       start_of_latest_foreign);
03732     mutex_exit(&dict_foreign_err_mutex);
03733 
03734     return(DB_CANNOT_ADD_CONSTRAINT);
03735   }
03736 
03737   /* Try to find an index which contains the columns as the first fields
03738   and in the right order, and the types are the same as in
03739   foreign->foreign_index */
03740 
03741   if (referenced_table) {
03742     index = dict_foreign_find_index(referenced_table,
03743             column_names, i,
03744             foreign->foreign_index,
03745             TRUE, FALSE);
03746     if (!index) {
03747       dict_foreign_free(foreign);
03748       mutex_enter(&dict_foreign_err_mutex);
03749       dict_foreign_error_report_low(ef, name);
03750       fprintf(ef, "%s:\n"
03751         "Cannot find an index in the"
03752         " referenced table where the\n"
03753         "referenced columns appear as the"
03754         " first columns, or column types\n"
03755         "in the table and the referenced table"
03756         " do not match for constraint.\n"
03757         "Note that the internal storage type of"
03758         " ENUM and SET changed in\n"
03759         "tables created with >= InnoDB-4.1.12,"
03760         " and such columns in old tables\n"
03761         "cannot be referenced by such columns"
03762         " in new tables.\n"
03763         "See " REFMAN
03764         "innodb-foreign-key-constraints.html\n"
03765         "for correct foreign key definition.\n",
03766         start_of_latest_foreign);
03767       mutex_exit(&dict_foreign_err_mutex);
03768 
03769       return(DB_PARENT_NO_INDEX);
03770     }
03771   } else {
03772     ut_a(trx->check_foreigns == FALSE);
03773     index = NULL;
03774   }
03775 
03776   foreign->referenced_index = index;
03777   foreign->referenced_table = referenced_table;
03778 
03779   foreign->referenced_table_name
03780     = mem_heap_strdup(foreign->heap, referenced_table_name);
03781 
03782   foreign->referenced_col_names = static_cast<const char **>(mem_heap_alloc(foreign->heap,
03783                    i * sizeof(void*)));
03784   for (i = 0; i < foreign->n_fields; i++) {
03785     foreign->referenced_col_names[i]
03786       = mem_heap_strdup(foreign->heap, column_names[i]);
03787   }
03788 
03789   /* We found an ok constraint definition: add to the lists */
03790 
03791   UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
03792 
03793   if (referenced_table) {
03794     UT_LIST_ADD_LAST(referenced_list,
03795          referenced_table->referenced_list,
03796          foreign);
03797   }
03798 
03799   goto loop;
03800 }
03801 
03802 /*********************************************************************/
03809 UNIV_INTERN
03810 ulint
03811 dict_create_foreign_constraints(
03812 /*============================*/
03813   trx_t*    trx,    
03814   const char* sql_string, 
03822   size_t    sql_length, 
03823   const char* name,   
03826   ibool   reject_fks) 
03829 {
03830   char*     str;
03831   ulint     err;
03832   mem_heap_t*   heap;
03833 
03834   ut_a(trx);
03835   ut_a(trx->mysql_thd);
03836 
03837   str = dict_strip_comments(sql_string, sql_length);
03838   heap = mem_heap_create(10000);
03839 
03840   err = dict_create_foreign_constraints_low(
03841     trx, heap, trx->session()->charset(), str, name,
03842     reject_fks);
03843 
03844   mem_heap_free(heap);
03845   mem_free(str);
03846 
03847   return(err);
03848 }
03849 
03850 /**********************************************************************/
03854 UNIV_INTERN
03855 ulint
03856 dict_foreign_parse_drop_constraints(
03857 /*================================*/
03858   mem_heap_t* heap,     
03860   trx_t*    trx,      
03861   dict_table_t* table,      
03862   ulint*    n,      
03864   const char*** constraints_to_drop)  
03866 {
03867   dict_foreign_t*   foreign;
03868   ibool     success;
03869   char*     str;
03870         size_t      len;
03871   const char*   ptr;
03872   const char*   id;
03873   FILE*     ef  = dict_foreign_err_file;
03874   const void* cs;
03875 
03876   ut_a(trx);
03877   ut_a(trx->mysql_thd);
03878 
03879   cs = trx->session()->charset();
03880 
03881   *n = 0;
03882 
03883   *constraints_to_drop = static_cast<const char **>(mem_heap_alloc(heap, 1000 * sizeof(char*)));
03884 
03885         ptr= trx->session()->getQueryStringCopy(len);
03886 
03887         str = dict_strip_comments(ptr, len);
03888 
03889   ptr = str;
03890 
03891   ut_ad(mutex_own(&(dict_sys->mutex)));
03892 loop:
03893   ptr = dict_scan_to(ptr, "DROP");
03894 
03895   if (*ptr == '\0') {
03896     mem_free(str);
03897 
03898     return(DB_SUCCESS);
03899   }
03900 
03901   ptr = dict_accept(cs, ptr, "DROP", &success);
03902 
03903   if (!innobase_isspace(cs, *ptr)) {
03904 
03905     goto loop;
03906   }
03907 
03908   ptr = dict_accept(cs, ptr, "FOREIGN", &success);
03909 
03910   if (!success || !innobase_isspace(cs, *ptr)) {
03911 
03912     goto loop;
03913   }
03914 
03915   ptr = dict_accept(cs, ptr, "KEY", &success);
03916 
03917   if (!success) {
03918 
03919     goto syntax_error;
03920   }
03921 
03922   ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
03923 
03924   if (id == NULL) {
03925 
03926     goto syntax_error;
03927   }
03928 
03929   ut_a(*n < 1000);
03930   (*constraints_to_drop)[*n] = id;
03931   (*n)++;
03932 
03933   /* Look for the given constraint id */
03934 
03935   foreign = UT_LIST_GET_FIRST(table->foreign_list);
03936 
03937   while (foreign != NULL) {
03938     if (0 == strcmp(foreign->id, id)
03939         || (strchr(foreign->id, '/')
03940       && 0 == strcmp(id,
03941                dict_remove_db_name(foreign->id)))) {
03942       /* Found */
03943       break;
03944     }
03945 
03946     foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
03947   }
03948 
03949   if (foreign == NULL) {
03950     mutex_enter(&dict_foreign_err_mutex);
03951     rewind(ef);
03952     ut_print_timestamp(ef);
03953     fputs(" Error in dropping of a foreign key constraint"
03954           " of table ", ef);
03955     ut_print_name(ef, NULL, TRUE, table->name);
03956     fputs(",\n"
03957           "in SQL command\n", ef);
03958     fputs(str, ef);
03959     fputs("\nCannot find a constraint with the given id ", ef);
03960     ut_print_name(ef, NULL, FALSE, id);
03961     fputs(".\n", ef);
03962     mutex_exit(&dict_foreign_err_mutex);
03963 
03964     mem_free(str);
03965 
03966     return(DB_CANNOT_DROP_CONSTRAINT);
03967   }
03968 
03969   goto loop;
03970 
03971 syntax_error:
03972   mutex_enter(&dict_foreign_err_mutex);
03973   rewind(ef);
03974   ut_print_timestamp(ef);
03975   fputs(" Syntax error in dropping of a"
03976         " foreign key constraint of table ", ef);
03977   ut_print_name(ef, NULL, TRUE, table->name);
03978   fprintf(ef, ",\n"
03979     "close to:\n%s\n in SQL command\n%s\n", ptr, str);
03980   mutex_exit(&dict_foreign_err_mutex);
03981 
03982   mem_free(str);
03983 
03984   return(DB_CANNOT_DROP_CONSTRAINT);
03985 }
03986 
03987 /*==================== END OF FOREIGN KEY PROCESSING ====================*/
03988 
03989 /**********************************************************************/
03993 UNIV_INTERN
03994 dict_index_t*
03995 dict_index_get_if_in_cache_low(
03996 /*===========================*/
03997   index_id_t  index_id) 
03998 {
03999   ut_ad(mutex_own(&(dict_sys->mutex)));
04000 
04001   return(dict_index_find_on_id_low(index_id));
04002 }
04003 
04004 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
04005 /**********************************************************************/
04008 UNIV_INTERN
04009 dict_index_t*
04010 dict_index_get_if_in_cache(
04011 /*=======================*/
04012   index_id_t  index_id) 
04013 {
04014   dict_index_t* index;
04015 
04016   if (dict_sys == NULL) {
04017     return(NULL);
04018   }
04019 
04020   mutex_enter(&(dict_sys->mutex));
04021 
04022   index = dict_index_get_if_in_cache_low(index_id);
04023 
04024   mutex_exit(&(dict_sys->mutex));
04025 
04026   return(index);
04027 }
04028 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
04029 
04030 #ifdef UNIV_DEBUG
04031 /**********************************************************************/
04035 UNIV_INTERN
04036 ibool
04037 dict_index_check_search_tuple(
04038 /*==========================*/
04039   const dict_index_t* index,  
04040   const dtuple_t*   tuple)  
04041 {
04042   ut_a(index);
04043   ut_a(dtuple_get_n_fields_cmp(tuple)
04044        <= dict_index_get_n_unique_in_tree(index));
04045   return(TRUE);
04046 }
04047 #endif /* UNIV_DEBUG */
04048 
04049 /**********************************************************************/
04052 UNIV_INTERN
04053 dtuple_t*
04054 dict_index_build_node_ptr(
04055 /*======================*/
04056   const dict_index_t* index,  
04057   const rec_t*    rec,  
04059   ulint     page_no,
04061   mem_heap_t*   heap, 
04063   ulint     level)  
04065 {
04066   dtuple_t* tuple;
04067   dfield_t* field;
04068   byte*   buf;
04069   ulint   n_unique;
04070 
04071   if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
04072     /* In a universal index tree, we take the whole record as
04073     the node pointer if the record is on the leaf level,
04074     on non-leaf levels we remove the last field, which
04075     contains the page number of the child page */
04076 
04077     ut_a(!dict_table_is_comp(index->table));
04078     n_unique = rec_get_n_fields_old(rec);
04079 
04080     if (level > 0) {
04081       ut_a(n_unique > 1);
04082       n_unique--;
04083     }
04084   } else {
04085     n_unique = dict_index_get_n_unique_in_tree(index);
04086   }
04087 
04088   tuple = dtuple_create(heap, n_unique + 1);
04089 
04090   /* When searching in the tree for the node pointer, we must not do
04091   comparison on the last field, the page number field, as on upper
04092   levels in the tree there may be identical node pointers with a
04093   different page number; therefore, we set the n_fields_cmp to one
04094   less: */
04095 
04096   dtuple_set_n_fields_cmp(tuple, n_unique);
04097 
04098   dict_index_copy_types(tuple, index, n_unique);
04099 
04100   buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
04101 
04102   mach_write_to_4(buf, page_no);
04103 
04104   field = dtuple_get_nth_field(tuple, n_unique);
04105   dfield_set_data(field, buf, 4);
04106 
04107   dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
04108 
04109   rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
04110   dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
04111            | REC_STATUS_NODE_PTR);
04112 
04113   ut_ad(dtuple_check_typed(tuple));
04114 
04115   return(tuple);
04116 }
04117 
04118 /**********************************************************************/
04122 UNIV_INTERN
04123 rec_t*
04124 dict_index_copy_rec_order_prefix(
04125 /*=============================*/
04126   const dict_index_t* index,  
04127   const rec_t*    rec,  
04129   ulint*      n_fields,
04130   byte**      buf,  
04132   ulint*      buf_size)
04133 {
04134   ulint   n;
04135 
04136   UNIV_PREFETCH_R(rec);
04137 
04138   if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
04139     ut_a(!dict_table_is_comp(index->table));
04140     n = rec_get_n_fields_old(rec);
04141   } else {
04142     n = dict_index_get_n_unique_in_tree(index);
04143   }
04144 
04145   *n_fields = n;
04146   return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
04147 }
04148 
04149 /**********************************************************************/
04152 UNIV_INTERN
04153 dtuple_t*
04154 dict_index_build_data_tuple(
04155 /*========================*/
04156   dict_index_t* index,  
04157   rec_t*    rec,  
04158   ulint   n_fields,
04159   mem_heap_t* heap) 
04160 {
04161   dtuple_t* tuple;
04162 
04163   ut_ad(dict_table_is_comp(index->table)
04164         || n_fields <= rec_get_n_fields_old(rec));
04165 
04166   tuple = dtuple_create(heap, n_fields);
04167 
04168   dict_index_copy_types(tuple, index, n_fields);
04169 
04170   rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
04171 
04172   ut_ad(dtuple_check_typed(tuple));
04173 
04174   return(tuple);
04175 }
04176 
04177 /*********************************************************************/
04179 UNIV_INTERN
04180 ulint
04181 dict_index_calc_min_rec_len(
04182 /*========================*/
04183   const dict_index_t* index)  
04184 {
04185   ulint sum = 0;
04186   ulint i;
04187   ulint comp  = dict_table_is_comp(index->table);
04188 
04189   if (comp) {
04190     ulint nullable = 0;
04191     sum = REC_N_NEW_EXTRA_BYTES;
04192     for (i = 0; i < dict_index_get_n_fields(index); i++) {
04193       const dict_col_t* col
04194         = dict_index_get_nth_col(index, i);
04195       ulint size = dict_col_get_fixed_size(col, comp);
04196       sum += size;
04197       if (!size) {
04198         size = col->len;
04199         sum += size < 128 ? 1 : 2;
04200       }
04201       if (!(col->prtype & DATA_NOT_NULL)) {
04202         nullable++;
04203       }
04204     }
04205 
04206     /* round the NULL flags up to full bytes */
04207     sum += UT_BITS_IN_BYTES(nullable);
04208 
04209     return(sum);
04210   }
04211 
04212   for (i = 0; i < dict_index_get_n_fields(index); i++) {
04213     sum += dict_col_get_fixed_size(
04214       dict_index_get_nth_col(index, i), comp);
04215   }
04216 
04217   if (sum > 127) {
04218     sum += 2 * dict_index_get_n_fields(index);
04219   } else {
04220     sum += dict_index_get_n_fields(index);
04221   }
04222 
04223   sum += REC_N_OLD_EXTRA_BYTES;
04224 
04225   return(sum);
04226 }
04227 
04228 /*********************************************************************/
04231 UNIV_INTERN
04232 void
04233 dict_update_statistics(
04234 /*===================*/
04235   dict_table_t* table,    
04236   ibool   only_calc_if_missing_stats)
04240 {
04241   dict_index_t* index;
04242   ulint   sum_of_index_sizes  = 0;
04243 
04244   if (table->ibd_file_missing) {
04245     ut_print_timestamp(stderr);
04246     fprintf(stderr,
04247       "  InnoDB: cannot calculate statistics for table %s\n"
04248       "InnoDB: because the .ibd file is missing.  For help,"
04249       " please refer to\n"
04250       "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
04251       table->name);
04252 
04253     return;
04254   }
04255 
04256   /* Find out the sizes of the indexes and how many different values
04257   for the key they approximately have */
04258 
04259   index = dict_table_get_first_index(table);
04260 
04261   if (index == NULL) {
04262     /* Table definition is corrupt */
04263 
04264     return;
04265   }
04266 
04267   dict_table_stats_lock(table, RW_X_LATCH);
04268 
04269   if (only_calc_if_missing_stats && table->stat_initialized) {
04270     dict_table_stats_unlock(table, RW_X_LATCH);
04271     return;
04272   }
04273 
04274   do {
04275     if (UNIV_LIKELY
04276         (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
04277          || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
04278        && dict_index_is_clust(index)))) {
04279       ulint size;
04280       size = btr_get_size(index, BTR_TOTAL_SIZE);
04281 
04282       index->stat_index_size = size;
04283 
04284       sum_of_index_sizes += size;
04285 
04286       size = btr_get_size(index, BTR_N_LEAF_PAGES);
04287 
04288       if (size == 0) {
04289         /* The root node of the tree is a leaf */
04290         size = 1;
04291       }
04292 
04293       index->stat_n_leaf_pages = size;
04294 
04295       btr_estimate_number_of_different_key_vals(index);
04296     } else {
04297       /* If we have set a high innodb_force_recovery
04298       level, do not calculate statistics, as a badly
04299       corrupted index can cause a crash in it.
04300       Initialize some bogus index cardinality
04301       statistics, so that the data can be queried in
04302       various means, also via secondary indexes. */
04303       ulint i;
04304 
04305       sum_of_index_sizes++;
04306       index->stat_index_size = index->stat_n_leaf_pages = 1;
04307 
04308       for (i = dict_index_get_n_unique(index); i; ) {
04309         index->stat_n_diff_key_vals[i--] = 1;
04310       }
04311     }
04312 
04313     index = dict_table_get_next_index(index);
04314   } while (index);
04315 
04316   index = dict_table_get_first_index(table);
04317 
04318   table->stat_n_rows = index->stat_n_diff_key_vals[
04319     dict_index_get_n_unique(index)];
04320 
04321   table->stat_clustered_index_size = index->stat_index_size;
04322 
04323   table->stat_sum_of_other_index_sizes = sum_of_index_sizes
04324     - index->stat_index_size;
04325 
04326   table->stat_initialized = TRUE;
04327 
04328   table->stat_modified_counter = 0;
04329 
04330   dict_table_stats_unlock(table, RW_X_LATCH);
04331 }
04332 
04333 /**********************************************************************/
04335 static
04336 void
04337 dict_foreign_print_low(
04338 /*===================*/
04339   dict_foreign_t* foreign)  
04340 {
04341   ulint i;
04342 
04343   ut_ad(mutex_own(&(dict_sys->mutex)));
04344 
04345   fprintf(stderr, "  FOREIGN KEY CONSTRAINT %s: %s (",
04346     foreign->id, foreign->foreign_table_name);
04347 
04348   for (i = 0; i < foreign->n_fields; i++) {
04349     fprintf(stderr, " %s", foreign->foreign_col_names[i]);
04350   }
04351 
04352   fprintf(stderr, " )\n"
04353     "             REFERENCES %s (",
04354     foreign->referenced_table_name);
04355 
04356   for (i = 0; i < foreign->n_fields; i++) {
04357     fprintf(stderr, " %s", foreign->referenced_col_names[i]);
04358   }
04359 
04360   fputs(" )\n", stderr);
04361 }
04362 
04363 /**********************************************************************/
04365 UNIV_INTERN
04366 void
04367 dict_table_print(
04368 /*=============*/
04369   dict_table_t* table)  
04370 {
04371   mutex_enter(&(dict_sys->mutex));
04372   dict_table_print_low(table);
04373   mutex_exit(&(dict_sys->mutex));
04374 }
04375 
04376 /**********************************************************************/
04378 UNIV_INTERN
04379 void
04380 dict_table_print_by_name(
04381 /*=====================*/
04382   const char* name) 
04383 {
04384   dict_table_t* table;
04385 
04386   mutex_enter(&(dict_sys->mutex));
04387 
04388   table = dict_table_get_low(name);
04389 
04390   ut_a(table);
04391 
04392   dict_table_print_low(table);
04393   mutex_exit(&(dict_sys->mutex));
04394 }
04395 
04396 /**********************************************************************/
04398 UNIV_INTERN
04399 void
04400 dict_table_print_low(
04401 /*=================*/
04402   dict_table_t* table)  
04403 {
04404   dict_index_t* index;
04405   dict_foreign_t* foreign;
04406   ulint   i;
04407 
04408   ut_ad(mutex_own(&(dict_sys->mutex)));
04409 
04410   dict_update_statistics(table, FALSE /* update even if initialized */);
04411 
04412   dict_table_stats_lock(table, RW_S_LATCH);
04413 
04414   fprintf(stderr,
04415     "--------------------------------------\n"
04416     "TABLE: name %s, id %llu, flags %lx, columns %lu,"
04417     " indexes %lu, appr.rows %lu\n"
04418     "  COLUMNS: ",
04419     table->name,
04420     (ullint) table->id,
04421     (ulong) table->flags,
04422     (ulong) table->n_cols,
04423     (ulong) UT_LIST_GET_LEN(table->indexes),
04424     (ulong) table->stat_n_rows);
04425 
04426   for (i = 0; i < (ulint) table->n_cols; i++) {
04427     dict_col_print_low(table, dict_table_get_nth_col(table, i));
04428     fputs("; ", stderr);
04429   }
04430 
04431   putc('\n', stderr);
04432 
04433   index = UT_LIST_GET_FIRST(table->indexes);
04434 
04435   while (index != NULL) {
04436     dict_index_print_low(index);
04437     index = UT_LIST_GET_NEXT(indexes, index);
04438   }
04439 
04440   dict_table_stats_unlock(table, RW_S_LATCH);
04441 
04442   foreign = UT_LIST_GET_FIRST(table->foreign_list);
04443 
04444   while (foreign != NULL) {
04445     dict_foreign_print_low(foreign);
04446     foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
04447   }
04448 
04449   foreign = UT_LIST_GET_FIRST(table->referenced_list);
04450 
04451   while (foreign != NULL) {
04452     dict_foreign_print_low(foreign);
04453     foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
04454   }
04455 }
04456 
04457 /**********************************************************************/
04459 static
04460 void
04461 dict_col_print_low(
04462 /*===============*/
04463   const dict_table_t* table,  
04464   const dict_col_t* col)  
04465 {
04466   dtype_t type;
04467 
04468   ut_ad(mutex_own(&(dict_sys->mutex)));
04469 
04470   dict_col_copy_type(col, &type);
04471   fprintf(stderr, "%s: ", dict_table_get_col_name(table,
04472               dict_col_get_no(col)));
04473 
04474   dtype_print(&type);
04475 }
04476 
04477 /**********************************************************************/
04479 static
04480 void
04481 dict_index_print_low(
04482 /*=================*/
04483   dict_index_t* index)  
04484 {
04485   ib_int64_t  n_vals;
04486   ulint   i;
04487 
04488   ut_ad(mutex_own(&(dict_sys->mutex)));
04489 
04490   if (index->n_user_defined_cols > 0) {
04491     n_vals = index->stat_n_diff_key_vals[
04492       index->n_user_defined_cols];
04493   } else {
04494     n_vals = index->stat_n_diff_key_vals[1];
04495   }
04496 
04497   fprintf(stderr,
04498     "  INDEX: name %s, id %llu, fields %lu/%lu,"
04499     " uniq %lu, type %lu\n"
04500     "   root page %lu, appr.key vals %lu,"
04501     " leaf pages %lu, size pages %lu\n"
04502     "   FIELDS: ",
04503     index->name,
04504     (ullint) index->id,
04505     (ulong) index->n_user_defined_cols,
04506     (ulong) index->n_fields,
04507     (ulong) index->n_uniq,
04508     (ulong) index->type,
04509     (ulong) index->page,
04510     (ulong) n_vals,
04511     (ulong) index->stat_n_leaf_pages,
04512     (ulong) index->stat_index_size);
04513 
04514   for (i = 0; i < index->n_fields; i++) {
04515     dict_field_print_low(dict_index_get_nth_field(index, i));
04516   }
04517 
04518   putc('\n', stderr);
04519 
04520 #ifdef UNIV_BTR_PRINT
04521   btr_print_size(index);
04522 
04523   btr_print_index(index, 7);
04524 #endif /* UNIV_BTR_PRINT */
04525 }
04526 
04527 /**********************************************************************/
04529 static
04530 void
04531 dict_field_print_low(
04532 /*=================*/
04533   const dict_field_t* field)  
04534 {
04535   ut_ad(mutex_own(&(dict_sys->mutex)));
04536 
04537   fprintf(stderr, " %s", field->name);
04538 
04539   if (field->prefix_len != 0) {
04540     fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
04541   }
04542 }
04543 
04544 /**********************************************************************/
04547 UNIV_INTERN
04548 void
04549 dict_print_info_on_foreign_key_in_create_format(
04550 /*============================================*/
04551   FILE*   file,   
04552   trx_t*    trx,    
04553   dict_foreign_t* foreign,  
04554   ibool   add_newline)  
04555 {
04556   const char* stripped_id;
04557   ulint i;
04558 
04559   if (strchr(foreign->id, '/')) {
04560     /* Strip the preceding database name from the constraint id */
04561     stripped_id = foreign->id + 1
04562       + dict_get_db_name_len(foreign->id);
04563   } else {
04564     stripped_id = foreign->id;
04565   }
04566 
04567   putc(',', file);
04568 
04569   if (add_newline) {
04570     /* SHOW CREATE TABLE wants constraints each printed nicely
04571     on its own line, while error messages want no newlines
04572     inserted. */
04573     fputs("\n ", file);
04574   }
04575 
04576   fputs(" CONSTRAINT ", file);
04577   ut_print_name(file, trx, FALSE, stripped_id);
04578   fputs(" FOREIGN KEY (", file);
04579 
04580   for (i = 0;;) {
04581     ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
04582     if (++i < foreign->n_fields) {
04583       fputs(", ", file);
04584     } else {
04585       break;
04586     }
04587   }
04588 
04589   fputs(") REFERENCES ", file);
04590 
04591   if (dict_tables_have_same_db(foreign->foreign_table_name,
04592              foreign->referenced_table_name)) {
04593     /* Do not print the database name of the referenced table */
04594     ut_print_name(file, trx, TRUE,
04595             dict_remove_db_name(
04596               foreign->referenced_table_name));
04597   } else {
04598     ut_print_name(file, trx, TRUE,
04599             foreign->referenced_table_name);
04600   }
04601 
04602   putc(' ', file);
04603   putc('(', file);
04604 
04605   for (i = 0;;) {
04606     ut_print_name(file, trx, FALSE,
04607             foreign->referenced_col_names[i]);
04608     if (++i < foreign->n_fields) {
04609       fputs(", ", file);
04610     } else {
04611       break;
04612     }
04613   }
04614 
04615   putc(')', file);
04616 
04617   if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
04618     fputs(" ON DELETE CASCADE", file);
04619   }
04620 
04621   if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
04622     fputs(" ON DELETE SET NULL", file);
04623   }
04624 
04625   if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
04626     fputs(" ON DELETE NO ACTION", file);
04627   }
04628 
04629   if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
04630     fputs(" ON UPDATE CASCADE", file);
04631   }
04632 
04633   if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
04634     fputs(" ON UPDATE SET NULL", file);
04635   }
04636 
04637   if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
04638     fputs(" ON UPDATE NO ACTION", file);
04639   }
04640 }
04641 
04642 /**********************************************************************/
04644 UNIV_INTERN
04645 void
04646 dict_print_info_on_foreign_keys(
04647 /*============================*/
04648   ibool   create_table_format, 
04652   FILE*   file, 
04653   trx_t*    trx,  
04654   dict_table_t* table)  
04655 {
04656   dict_foreign_t* foreign;
04657 
04658   mutex_enter(&(dict_sys->mutex));
04659 
04660   foreign = UT_LIST_GET_FIRST(table->foreign_list);
04661 
04662   if (foreign == NULL) {
04663     mutex_exit(&(dict_sys->mutex));
04664 
04665     return;
04666   }
04667 
04668   while (foreign != NULL) {
04669     if (create_table_format) {
04670       dict_print_info_on_foreign_key_in_create_format(
04671         file, trx, foreign, TRUE);
04672     } else {
04673       ulint i;
04674       fputs("; (", file);
04675 
04676       for (i = 0; i < foreign->n_fields; i++) {
04677         if (i) {
04678           putc(' ', file);
04679         }
04680 
04681         ut_print_name(file, trx, FALSE,
04682                 foreign->foreign_col_names[i]);
04683       }
04684 
04685       fputs(") REFER ", file);
04686       ut_print_name(file, trx, TRUE,
04687               foreign->referenced_table_name);
04688       putc('(', file);
04689 
04690       for (i = 0; i < foreign->n_fields; i++) {
04691         if (i) {
04692           putc(' ', file);
04693         }
04694         ut_print_name(
04695           file, trx, FALSE,
04696           foreign->referenced_col_names[i]);
04697       }
04698 
04699       putc(')', file);
04700 
04701       if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
04702         fputs(" ON DELETE CASCADE", file);
04703       }
04704 
04705       if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
04706         fputs(" ON DELETE SET NULL", file);
04707       }
04708 
04709       if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
04710         fputs(" ON DELETE NO ACTION", file);
04711       }
04712 
04713       if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
04714         fputs(" ON UPDATE CASCADE", file);
04715       }
04716 
04717       if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
04718         fputs(" ON UPDATE SET NULL", file);
04719       }
04720 
04721       if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
04722         fputs(" ON UPDATE NO ACTION", file);
04723       }
04724     }
04725 
04726     foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
04727   }
04728 
04729   mutex_exit(&(dict_sys->mutex));
04730 }
04731 
04732 /********************************************************************/
04734 UNIV_INTERN
04735 void
04736 dict_index_name_print(
04737 /*==================*/
04738   FILE*     file, 
04739   trx_t*      trx,  
04740   const dict_index_t* index)  
04741 {
04742   fputs("index ", file);
04743   ut_print_name(file, trx, FALSE, index->name);
04744   fputs(" of table ", file);
04745   ut_print_name(file, trx, TRUE, index->table_name);
04746 }
04747 #endif /* !UNIV_HOTBACKUP */
04748 
04749 /**********************************************************************/
04751 UNIV_INTERN
04752 void
04753 dict_ind_init(void)
04754 /*===============*/
04755 {
04756   dict_table_t*   table;
04757 
04758   /* create dummy table and index for REDUNDANT infimum and supremum */
04759   table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0);
04760   dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
04761              DATA_ENGLISH | DATA_NOT_NULL, 8);
04762 
04763   dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
04764                DICT_HDR_SPACE, 0, 1);
04765   dict_index_add_col(dict_ind_redundant, table,
04766          dict_table_get_nth_col(table, 0), 0);
04767   dict_ind_redundant->table = table;
04768   /* create dummy table and index for COMPACT infimum and supremum */
04769   table = dict_mem_table_create("SYS_DUMMY2",
04770               DICT_HDR_SPACE, 1, DICT_TF_COMPACT);
04771   dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
04772              DATA_ENGLISH | DATA_NOT_NULL, 8);
04773   dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
04774              DICT_HDR_SPACE, 0, 1);
04775   dict_index_add_col(dict_ind_compact, table,
04776          dict_table_get_nth_col(table, 0), 0);
04777   dict_ind_compact->table = table;
04778 
04779   /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
04780   dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
04781 }
04782 
04783 /**********************************************************************/
04785 static
04786 void
04787 dict_ind_free(void)
04788 /*===============*/
04789 {
04790   dict_table_t* table;
04791 
04792   table = dict_ind_compact->table;
04793   dict_mem_index_free(dict_ind_compact);
04794   dict_ind_compact = NULL;
04795   dict_mem_table_free(table);
04796 
04797   table = dict_ind_redundant->table;
04798   dict_mem_index_free(dict_ind_redundant);
04799   dict_ind_redundant = NULL;
04800   dict_mem_table_free(table);
04801 }
04802 
04803 #ifndef UNIV_HOTBACKUP
04804 /**********************************************************************/
04807 UNIV_INTERN
04808 dict_index_t*
04809 dict_table_get_index_on_name(
04810 /*=========================*/
04811   dict_table_t* table,  
04812   const char* name) 
04813 {
04814   dict_index_t* index;
04815 
04816   index = dict_table_get_first_index(table);
04817 
04818   while (index != NULL) {
04819     if (ut_strcmp(index->name, name) == 0) {
04820 
04821       return(index);
04822     }
04823 
04824     index = dict_table_get_next_index(index);
04825   }
04826 
04827   return(NULL);
04828 
04829 }
04830 
04831 /**********************************************************************/
04834 UNIV_INTERN
04835 void
04836 dict_table_replace_index_in_foreign_list(
04837 /*=====================================*/
04838   dict_table_t* table,  
04839   dict_index_t* index,  
04840   const trx_t*  trx)  
04841 {
04842   dict_foreign_t* foreign;
04843 
04844   for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
04845        foreign;
04846        foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
04847 
04848     if (foreign->foreign_index == index) {
04849       dict_index_t* new_index
04850         = dict_foreign_find_equiv_index(foreign);
04851 
04852       /* There must exist an alternative index if
04853       check_foreigns (FOREIGN_KEY_CHECKS) is on, 
04854       since ha_innobase::prepare_drop_index had done
04855       the check before we reach here. */
04856 
04857       ut_a(new_index || !trx->check_foreigns);
04858 
04859       foreign->foreign_index = new_index;
04860     }
04861   }
04862 }
04863 
04864 /**********************************************************************/
04868 UNIV_INTERN
04869 dict_index_t*
04870 dict_table_get_index_on_name_and_min_id(
04871 /*=====================================*/
04872   dict_table_t* table,  
04873   const char* name) 
04874 {
04875   dict_index_t* index;
04876   dict_index_t* min_index; /* Index with matching name and min(id) */
04877 
04878   min_index = NULL;
04879   index = dict_table_get_first_index(table);
04880 
04881   while (index != NULL) {
04882     if (ut_strcmp(index->name, name) == 0) {
04883       if (!min_index || index->id < min_index->id) {
04884 
04885         min_index = index;
04886       }
04887     }
04888 
04889     index = dict_table_get_next_index(index);
04890   }
04891 
04892   return(min_index);
04893 
04894 }
04895 
04896 #ifdef UNIV_DEBUG
04897 /**********************************************************************/
04899 UNIV_INTERN
04900 void
04901 dict_table_check_for_dup_indexes(
04902 /*=============================*/
04903   const dict_table_t* table,  
04905   ibool     tmp_ok) 
04907 {
04908   /* Check for duplicates, ignoring indexes that are marked
04909   as to be dropped */
04910 
04911   const dict_index_t* index1;
04912   const dict_index_t* index2;
04913 
04914   ut_ad(mutex_own(&dict_sys->mutex));
04915 
04916   /* The primary index _must_ exist */
04917   ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
04918 
04919   index1 = UT_LIST_GET_FIRST(table->indexes);
04920 
04921   do {
04922     ut_ad(tmp_ok || *index1->name != TEMP_INDEX_PREFIX);
04923 
04924     index2 = UT_LIST_GET_NEXT(indexes, index1);
04925 
04926     while (index2) {
04927 
04928       if (!index2->to_be_dropped) {
04929         ut_ad(ut_strcmp(index1->name, index2->name));
04930       }
04931 
04932       index2 = UT_LIST_GET_NEXT(indexes, index2);
04933     }
04934 
04935     index1 = UT_LIST_GET_NEXT(indexes, index1);
04936   } while (index1);
04937 }
04938 #endif /* UNIV_DEBUG */
04939 
04940 /**************************************************************************
04941 Closes the data dictionary module. */
04942 UNIV_INTERN
04943 void
04944 dict_close(void)
04945 /*============*/
04946 {
04947   ulint i;
04948 
04949   /* Free the hash elements. We don't remove them from the table
04950   because we are going to destroy the table anyway. */
04951   for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
04952     dict_table_t* table;
04953 
04954     table = static_cast<dict_table_t *>(HASH_GET_FIRST(dict_sys->table_hash, i));
04955 
04956     while (table) {
04957       dict_table_t* prev_table = table;
04958 
04959       table = static_cast<dict_table_t *>(HASH_GET_NEXT(name_hash, prev_table));
04960 #ifdef UNIV_DEBUG
04961       ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
04962 #endif
04963       /* Acquire only because it's a pre-condition. */
04964       mutex_enter(&dict_sys->mutex);
04965 
04966       dict_table_remove_from_cache(prev_table);
04967 
04968       mutex_exit(&dict_sys->mutex);
04969     }
04970   }
04971 
04972   hash_table_free(dict_sys->table_hash);
04973 
04974   /* The elements are the same instance as in dict_sys->table_hash,
04975   therefore we don't delete the individual elements. */
04976   hash_table_free(dict_sys->table_id_hash);
04977 
04978   dict_ind_free();
04979 
04980   mutex_free(&dict_sys->mutex);
04981 
04982   rw_lock_free(&dict_operation_lock);
04983   memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));
04984 
04985   mutex_free(&dict_foreign_err_mutex);
04986 
04987   mem_free(dict_sys);
04988   dict_sys = NULL;
04989 
04990   for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
04991     rw_lock_free(&dict_table_stats_latches[i]);
04992   }
04993 }
04994 #endif /* !UNIV_HOTBACKUP */