Drizzled Public API Documentation

dict0crea.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 "dict0crea.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "dict0crea.ic"
00030 #endif
00031 
00032 #include "btr0pcur.h"
00033 #include "btr0btr.h"
00034 #include "page0page.h"
00035 #include "mach0data.h"
00036 #include "dict0boot.h"
00037 #include "dict0dict.h"
00038 #include "que0que.h"
00039 #include "row0ins.h"
00040 #include "row0mysql.h"
00041 #include "pars0pars.h"
00042 #include "trx0roll.h"
00043 #include "usr0sess.h"
00044 #include "ut0vec.h"
00045 
00046 /*****************************************************************/
00050 static
00051 dtuple_t*
00052 dict_create_sys_tables_tuple(
00053 /*=========================*/
00054   const dict_table_t* table,  
00055   mem_heap_t*   heap) 
00058 {
00059   dict_table_t* sys_tables;
00060   dtuple_t* entry;
00061   dfield_t* dfield;
00062   byte*   ptr;
00063 
00064   ut_ad(table);
00065   ut_ad(heap);
00066 
00067   sys_tables = dict_sys->sys_tables;
00068 
00069   entry = dtuple_create(heap, 8 + DATA_N_SYS_COLS);
00070 
00071   dict_table_copy_types(entry, sys_tables);
00072 
00073   /* 0: NAME -----------------------------*/
00074   dfield = dtuple_get_nth_field(entry, 0/*NAME*/);
00075 
00076   dfield_set_data(dfield, table->name, ut_strlen(table->name));
00077   /* 3: ID -------------------------------*/
00078   dfield = dtuple_get_nth_field(entry, 1/*ID*/);
00079 
00080   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
00081   mach_write_to_8(ptr, table->id);
00082 
00083   dfield_set_data(dfield, ptr, 8);
00084   /* 4: N_COLS ---------------------------*/
00085   dfield = dtuple_get_nth_field(entry, 2/*N_COLS*/);
00086 
00087 #if DICT_TF_COMPACT != 1
00088 #error
00089 #endif
00090 
00091   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00092   mach_write_to_4(ptr, table->n_def
00093       | ((table->flags & DICT_TF_COMPACT) << 31));
00094   dfield_set_data(dfield, ptr, 4);
00095   /* 5: TYPE -----------------------------*/
00096   dfield = dtuple_get_nth_field(entry, 3/*TYPE*/);
00097 
00098   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00099   if (table->flags & (~DICT_TF_COMPACT & ~(~0 << DICT_TF_BITS))) {
00100     ut_a(table->flags & DICT_TF_COMPACT);
00101     ut_a(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
00102     ut_a((table->flags & DICT_TF_ZSSIZE_MASK)
00103          <= (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT));
00104     ut_a(!(table->flags & (~0 << DICT_TF2_BITS)));
00105     mach_write_to_4(ptr, table->flags & ~(~0 << DICT_TF_BITS));
00106   } else {
00107     mach_write_to_4(ptr, DICT_TABLE_ORDINARY);
00108   }
00109 
00110   dfield_set_data(dfield, ptr, 4);
00111   /* 6: MIX_ID (obsolete) ---------------------------*/
00112   dfield = dtuple_get_nth_field(entry, 4/*MIX_ID*/);
00113 
00114   ptr = static_cast<unsigned char *>(mem_heap_zalloc(heap, 8));
00115 
00116   dfield_set_data(dfield, ptr, 8);
00117   /* 7: MIX_LEN (additional flags) --------------------------*/
00118 
00119   dfield = dtuple_get_nth_field(entry, 5/*MIX_LEN*/);
00120 
00121   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00122   mach_write_to_4(ptr, table->flags >> DICT_TF2_SHIFT);
00123 
00124   dfield_set_data(dfield, ptr, 4);
00125   /* 8: CLUSTER_NAME ---------------------*/
00126   dfield = dtuple_get_nth_field(entry, 6/*CLUSTER_NAME*/);
00127   dfield_set_null(dfield); /* not supported */
00128 
00129   /* 9: SPACE ----------------------------*/
00130   dfield = dtuple_get_nth_field(entry, 7/*SPACE*/);
00131 
00132   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00133   mach_write_to_4(ptr, table->space);
00134 
00135   dfield_set_data(dfield, ptr, 4);
00136   /*----------------------------------*/
00137 
00138   return(entry);
00139 }
00140 
00141 /*****************************************************************/
00145 static
00146 dtuple_t*
00147 dict_create_sys_columns_tuple(
00148 /*==========================*/
00149   const dict_table_t* table,  
00150   ulint     i,  
00151   mem_heap_t*   heap) 
00154 {
00155   dict_table_t*   sys_columns;
00156   dtuple_t*   entry;
00157   const dict_col_t* column;
00158   dfield_t*   dfield;
00159   byte*     ptr;
00160   const char*   col_name;
00161 
00162   ut_ad(table);
00163   ut_ad(heap);
00164 
00165   column = dict_table_get_nth_col(table, i);
00166 
00167   sys_columns = dict_sys->sys_columns;
00168 
00169   entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);
00170 
00171   dict_table_copy_types(entry, sys_columns);
00172 
00173   /* 0: TABLE_ID -----------------------*/
00174   dfield = dtuple_get_nth_field(entry, 0/*TABLE_ID*/);
00175 
00176   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
00177   mach_write_to_8(ptr, table->id);
00178 
00179   dfield_set_data(dfield, ptr, 8);
00180   /* 1: POS ----------------------------*/
00181   dfield = dtuple_get_nth_field(entry, 1/*POS*/);
00182 
00183   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00184   mach_write_to_4(ptr, i);
00185 
00186   dfield_set_data(dfield, ptr, 4);
00187   /* 4: NAME ---------------------------*/
00188   dfield = dtuple_get_nth_field(entry, 2/*NAME*/);
00189 
00190   col_name = dict_table_get_col_name(table, i);
00191   dfield_set_data(dfield, col_name, ut_strlen(col_name));
00192   /* 5: MTYPE --------------------------*/
00193   dfield = dtuple_get_nth_field(entry, 3/*MTYPE*/);
00194 
00195   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00196   mach_write_to_4(ptr, column->mtype);
00197 
00198   dfield_set_data(dfield, ptr, 4);
00199   /* 6: PRTYPE -------------------------*/
00200   dfield = dtuple_get_nth_field(entry, 4/*PRTYPE*/);
00201 
00202   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00203   mach_write_to_4(ptr, column->prtype);
00204 
00205   dfield_set_data(dfield, ptr, 4);
00206   /* 7: LEN ----------------------------*/
00207   dfield = dtuple_get_nth_field(entry, 5/*LEN*/);
00208 
00209   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00210   mach_write_to_4(ptr, column->len);
00211 
00212   dfield_set_data(dfield, ptr, 4);
00213   /* 8: PREC ---------------------------*/
00214   dfield = dtuple_get_nth_field(entry, 6/*PREC*/);
00215 
00216   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00217   mach_write_to_4(ptr, 0/* unused */);
00218 
00219   dfield_set_data(dfield, ptr, 4);
00220   /*---------------------------------*/
00221 
00222   return(entry);
00223 }
00224 
00225 /***************************************************************/
00228 static
00229 ulint
00230 dict_build_table_def_step(
00231 /*======================*/
00232   que_thr_t*  thr,  
00233   tab_node_t* node) 
00234 {
00235   dict_table_t* table;
00236   dtuple_t* row;
00237   ulint   error;
00238   ulint   flags;
00239   const char* path_or_name;
00240   ibool   is_path;
00241   mtr_t   mtr;
00242   ulint   space = 0;
00243   ibool   file_per_table;
00244 
00245   ut_ad(mutex_own(&(dict_sys->mutex)));
00246 
00247   table = node->table;
00248 
00249   /* Cache the global variable "srv_file_per_table" to
00250   a local variable before using it. Please note
00251   "srv_file_per_table" is not under dict_sys mutex
00252   protection, and could be changed while executing
00253   this function. So better to cache the current value
00254   to a local variable, and all future reference to
00255   "srv_file_per_table" should use this local variable. */
00256   file_per_table = srv_file_per_table;
00257 
00258   dict_hdr_get_new_id(&table->id, NULL, NULL);
00259 
00260   thr_get_trx(thr)->table_id = table->id;
00261 
00262   if (file_per_table) {
00263     /* Get a new space id if srv_file_per_table is set */
00264     dict_hdr_get_new_id(NULL, NULL, &space);
00265 
00266     if (UNIV_UNLIKELY(space == ULINT_UNDEFINED)) {
00267       return(DB_ERROR);
00268     }
00269 
00270     /* We create a new single-table tablespace for the table.
00271     We initially let it be 4 pages:
00272     - page 0 is the fsp header and an extent descriptor page,
00273     - page 1 is an ibuf bitmap page,
00274     - page 2 is the first inode page,
00275     - page 3 will contain the root of the clustered index of the
00276     table we create here. */
00277 
00278     if (table->dir_path_of_temp_table) {
00279       /* We place tables created with CREATE TEMPORARY
00280       TABLE in the tmp dir of mysqld server */
00281 
00282       path_or_name = table->dir_path_of_temp_table;
00283       is_path = TRUE;
00284     } else {
00285       path_or_name = table->name;
00286       is_path = FALSE;
00287     }
00288 
00289     ut_ad(dict_table_get_format(table) <= DICT_TF_FORMAT_MAX);
00290     ut_ad(!dict_table_zip_size(table)
00291           || dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
00292 
00293     flags = table->flags & ~(~0 << DICT_TF_BITS);
00294     error = fil_create_new_single_table_tablespace(
00295       space, path_or_name, is_path,
00296       flags == DICT_TF_COMPACT ? 0 : flags,
00297       FIL_IBD_FILE_INITIAL_SIZE);
00298     table->space = (unsigned int) space;
00299 
00300     if (error != DB_SUCCESS) {
00301 
00302       return(error);
00303     }
00304 
00305     mtr_start(&mtr);
00306 
00307     fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
00308 
00309     mtr_commit(&mtr);
00310   } else {
00311     /* Create in the system tablespace: disallow new features */
00312     table->flags &= (~0 << DICT_TF_BITS) | DICT_TF_COMPACT;
00313   }
00314 
00315   row = dict_create_sys_tables_tuple(table, node->heap);
00316 
00317   ins_node_set_new_row(node->tab_def, row);
00318 
00319   return(DB_SUCCESS);
00320 }
00321 
00322 /***************************************************************/
00325 static
00326 ulint
00327 dict_build_col_def_step(
00328 /*====================*/
00329   tab_node_t* node) 
00330 {
00331   dtuple_t* row;
00332 
00333   row = dict_create_sys_columns_tuple(node->table, node->col_no,
00334               node->heap);
00335   ins_node_set_new_row(node->col_def, row);
00336 
00337   return(DB_SUCCESS);
00338 }
00339 
00340 /*****************************************************************/
00344 static
00345 dtuple_t*
00346 dict_create_sys_indexes_tuple(
00347 /*==========================*/
00348   const dict_index_t* index,  
00349   mem_heap_t*   heap) 
00352 {
00353   dict_table_t* sys_indexes;
00354   dict_table_t* table;
00355   dtuple_t* entry;
00356   dfield_t* dfield;
00357   byte*   ptr;
00358 
00359   ut_ad(mutex_own(&(dict_sys->mutex)));
00360   ut_ad(index);
00361   ut_ad(heap);
00362 
00363   sys_indexes = dict_sys->sys_indexes;
00364 
00365   table = dict_table_get_low(index->table_name);
00366 
00367   entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);
00368 
00369   dict_table_copy_types(entry, sys_indexes);
00370 
00371   /* 0: TABLE_ID -----------------------*/
00372   dfield = dtuple_get_nth_field(entry, 0/*TABLE_ID*/);
00373 
00374   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
00375   mach_write_to_8(ptr, table->id);
00376 
00377   dfield_set_data(dfield, ptr, 8);
00378   /* 1: ID ----------------------------*/
00379   dfield = dtuple_get_nth_field(entry, 1/*ID*/);
00380 
00381   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
00382   mach_write_to_8(ptr, index->id);
00383 
00384   dfield_set_data(dfield, ptr, 8);
00385   /* 4: NAME --------------------------*/
00386   dfield = dtuple_get_nth_field(entry, 2/*NAME*/);
00387 
00388   dfield_set_data(dfield, index->name, ut_strlen(index->name));
00389   /* 5: N_FIELDS ----------------------*/
00390   dfield = dtuple_get_nth_field(entry, 3/*N_FIELDS*/);
00391 
00392   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00393   mach_write_to_4(ptr, index->n_fields);
00394 
00395   dfield_set_data(dfield, ptr, 4);
00396   /* 6: TYPE --------------------------*/
00397   dfield = dtuple_get_nth_field(entry, 4/*TYPE*/);
00398 
00399   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00400   mach_write_to_4(ptr, index->type);
00401 
00402   dfield_set_data(dfield, ptr, 4);
00403   /* 7: SPACE --------------------------*/
00404 
00405 #if DICT_SYS_INDEXES_SPACE_NO_FIELD != 7
00406 #error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 7"
00407 #endif
00408 
00409   dfield = dtuple_get_nth_field(entry, 5/*SPACE*/);
00410 
00411   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00412   mach_write_to_4(ptr, index->space);
00413 
00414   dfield_set_data(dfield, ptr, 4);
00415   /* 8: PAGE_NO --------------------------*/
00416 
00417 #if DICT_SYS_INDEXES_PAGE_NO_FIELD != 8
00418 #error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 8"
00419 #endif
00420 
00421   dfield = dtuple_get_nth_field(entry, 6/*PAGE_NO*/);
00422 
00423   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00424   mach_write_to_4(ptr, FIL_NULL);
00425 
00426   dfield_set_data(dfield, ptr, 4);
00427   /*--------------------------------*/
00428 
00429   return(entry);
00430 }
00431 
00432 /*****************************************************************/
00436 static
00437 dtuple_t*
00438 dict_create_sys_fields_tuple(
00439 /*=========================*/
00440   const dict_index_t* index,  
00441   ulint     i,  
00442   mem_heap_t*   heap) 
00445 {
00446   dict_table_t* sys_fields;
00447   dtuple_t* entry;
00448   dict_field_t* field;
00449   dfield_t* dfield;
00450   byte*   ptr;
00451   ibool   index_contains_column_prefix_field  = FALSE;
00452   ulint   j;
00453 
00454   ut_ad(index);
00455   ut_ad(heap);
00456 
00457   for (j = 0; j < index->n_fields; j++) {
00458     if (dict_index_get_nth_field(index, j)->prefix_len > 0) {
00459       index_contains_column_prefix_field = TRUE;
00460       break;
00461     }
00462   }
00463 
00464   field = dict_index_get_nth_field(index, i);
00465 
00466   sys_fields = dict_sys->sys_fields;
00467 
00468   entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
00469 
00470   dict_table_copy_types(entry, sys_fields);
00471 
00472   /* 0: INDEX_ID -----------------------*/
00473   dfield = dtuple_get_nth_field(entry, 0/*INDEX_ID*/);
00474 
00475   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
00476   mach_write_to_8(ptr, index->id);
00477 
00478   dfield_set_data(dfield, ptr, 8);
00479   /* 1: POS + PREFIX LENGTH ----------------------------*/
00480 
00481   dfield = dtuple_get_nth_field(entry, 1/*POS*/);
00482 
00483   ptr = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
00484 
00485   if (index_contains_column_prefix_field) {
00486     /* If there are column prefix fields in the index, then
00487     we store the number of the field to the 2 HIGH bytes
00488     and the prefix length to the 2 low bytes, */
00489 
00490     mach_write_to_4(ptr, (i << 16) + field->prefix_len);
00491   } else {
00492     /* Else we store the number of the field to the 2 LOW bytes.
00493     This is to keep the storage format compatible with
00494     InnoDB versions < 4.0.14. */
00495 
00496     mach_write_to_4(ptr, i);
00497   }
00498 
00499   dfield_set_data(dfield, ptr, 4);
00500   /* 4: COL_NAME -------------------------*/
00501   dfield = dtuple_get_nth_field(entry, 2/*COL_NAME*/);
00502 
00503   dfield_set_data(dfield, field->name,
00504       ut_strlen(field->name));
00505   /*---------------------------------*/
00506 
00507   return(entry);
00508 }
00509 
00510 /*****************************************************************/
00514 static
00515 dtuple_t*
00516 dict_create_search_tuple(
00517 /*=====================*/
00518   const dtuple_t* tuple,  
00520   mem_heap_t* heap) 
00522 {
00523   dtuple_t* search_tuple;
00524   const dfield_t* field1;
00525   dfield_t* field2;
00526 
00527   ut_ad(tuple && heap);
00528 
00529   search_tuple = dtuple_create(heap, 2);
00530 
00531   field1 = dtuple_get_nth_field(tuple, 0);
00532   field2 = dtuple_get_nth_field(search_tuple, 0);
00533 
00534   dfield_copy(field2, field1);
00535 
00536   field1 = dtuple_get_nth_field(tuple, 1);
00537   field2 = dtuple_get_nth_field(search_tuple, 1);
00538 
00539   dfield_copy(field2, field1);
00540 
00541   ut_ad(dtuple_validate(search_tuple));
00542 
00543   return(search_tuple);
00544 }
00545 
00546 /***************************************************************/
00549 static
00550 ulint
00551 dict_build_index_def_step(
00552 /*======================*/
00553   que_thr_t*  thr,  
00554   ind_node_t* node) 
00555 {
00556   dict_table_t* table;
00557   dict_index_t* index;
00558   dtuple_t* row;
00559   trx_t*    trx;
00560 
00561   ut_ad(mutex_own(&(dict_sys->mutex)));
00562 
00563   trx = thr_get_trx(thr);
00564 
00565   index = node->index;
00566 
00567   table = dict_table_get_low(index->table_name);
00568 
00569   if (table == NULL) {
00570     return(DB_TABLE_NOT_FOUND);
00571   }
00572 
00573   trx->table_id = table->id;
00574 
00575   node->table = table;
00576 
00577   ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
00578         || dict_index_is_clust(index));
00579 
00580   dict_hdr_get_new_id(NULL, &index->id, NULL);
00581 
00582   /* Inherit the space id from the table; we store all indexes of a
00583   table in the same tablespace */
00584 
00585   index->space = table->space;
00586   node->page_no = FIL_NULL;
00587   row = dict_create_sys_indexes_tuple(index, node->heap);
00588   node->ind_row = row;
00589 
00590   ins_node_set_new_row(node->ind_def, row);
00591 
00592   /* Note that the index was created by this transaction. */
00593   index->trx_id = trx->id;
00594 
00595   return(DB_SUCCESS);
00596 }
00597 
00598 /***************************************************************/
00601 static
00602 ulint
00603 dict_build_field_def_step(
00604 /*======================*/
00605   ind_node_t* node) 
00606 {
00607   dict_index_t* index;
00608   dtuple_t* row;
00609 
00610   index = node->index;
00611 
00612   row = dict_create_sys_fields_tuple(index, node->field_no, node->heap);
00613 
00614   ins_node_set_new_row(node->field_def, row);
00615 
00616   return(DB_SUCCESS);
00617 }
00618 
00619 /***************************************************************/
00622 static
00623 ulint
00624 dict_create_index_tree_step(
00625 /*========================*/
00626   ind_node_t* node) 
00627 {
00628   dict_index_t* index;
00629   dict_table_t* sys_indexes;
00630   dtuple_t* search_tuple;
00631   ulint   zip_size;
00632   btr_pcur_t  pcur;
00633   mtr_t   mtr;
00634 
00635   ut_ad(mutex_own(&(dict_sys->mutex)));
00636 
00637   index = node->index;
00638 
00639   sys_indexes = dict_sys->sys_indexes;
00640 
00641   /* Run a mini-transaction in which the index tree is allocated for
00642   the index and its root address is written to the index entry in
00643   sys_indexes */
00644 
00645   mtr_start(&mtr);
00646 
00647   search_tuple = dict_create_search_tuple(node->ind_row, node->heap);
00648 
00649   btr_pcur_open(UT_LIST_GET_FIRST(sys_indexes->indexes),
00650           search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF,
00651           &pcur, &mtr);
00652 
00653   btr_pcur_move_to_next_user_rec(&pcur, &mtr);
00654 
00655   zip_size = dict_table_zip_size(index->table);
00656 
00657   node->page_no = btr_create(index->type, index->space, zip_size,
00658            index->id, index, &mtr);
00659   /* printf("Created a new index tree in space %lu root page %lu\n",
00660   index->space, index->page_no); */
00661 
00662   page_rec_write_index_page_no(btr_pcur_get_rec(&pcur),
00663              DICT_SYS_INDEXES_PAGE_NO_FIELD,
00664              node->page_no, &mtr);
00665   btr_pcur_close(&pcur);
00666   mtr_commit(&mtr);
00667 
00668   if (node->page_no == FIL_NULL) {
00669 
00670     return(DB_OUT_OF_FILE_SPACE);
00671   }
00672 
00673   return(DB_SUCCESS);
00674 }
00675 
00676 /*******************************************************************/
00678 UNIV_INTERN
00679 void
00680 dict_drop_index_tree(
00681 /*=================*/
00682   rec_t*  rec,  
00684   mtr_t*  mtr)  
00685 {
00686   ulint   root_page_no;
00687   ulint   space;
00688   ulint   zip_size;
00689   const byte* ptr;
00690   ulint   len;
00691 
00692   ut_ad(mutex_own(&(dict_sys->mutex)));
00693   ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
00694   ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);
00695 
00696   ut_ad(len == 4);
00697 
00698   root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
00699 
00700   if (root_page_no == FIL_NULL) {
00701     /* The tree has already been freed */
00702 
00703     return;
00704   }
00705 
00706   ptr = rec_get_nth_field_old(rec,
00707             DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
00708 
00709   ut_ad(len == 4);
00710 
00711   space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
00712   zip_size = fil_space_get_zip_size(space);
00713 
00714   if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
00715     /* It is a single table tablespace and the .ibd file is
00716     missing: do nothing */
00717 
00718     return;
00719   }
00720 
00721   /* We free all the pages but the root page first; this operation
00722   may span several mini-transactions */
00723 
00724   btr_free_but_not_root(space, zip_size, root_page_no);
00725 
00726   /* Then we free the root page in the same mini-transaction where
00727   we write FIL_NULL to the appropriate field in the SYS_INDEXES
00728   record: this mini-transaction marks the B-tree totally freed */
00729 
00730   /* printf("Dropping index tree in space %lu root page %lu\n", space,
00731   root_page_no); */
00732   btr_free_root(space, zip_size, root_page_no, mtr);
00733 
00734   page_rec_write_index_page_no(rec,
00735              DICT_SYS_INDEXES_PAGE_NO_FIELD,
00736              FIL_NULL, mtr);
00737 }
00738 
00739 /*******************************************************************/
00742 UNIV_INTERN
00743 ulint
00744 dict_truncate_index_tree(
00745 /*=====================*/
00746   dict_table_t* table,  
00747   ulint   space,  
00750   btr_pcur_t* pcur, 
00754   mtr_t*    mtr)  
00757 {
00758   ulint   root_page_no;
00759   ibool   drop = !space;
00760   ulint   zip_size;
00761   ulint   type;
00762   index_id_t  index_id;
00763   rec_t*    rec;
00764   const byte* ptr;
00765   ulint   len;
00766   dict_index_t* index;
00767 
00768   ut_ad(mutex_own(&(dict_sys->mutex)));
00769   ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
00770   rec = btr_pcur_get_rec(pcur);
00771   ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);
00772 
00773   ut_ad(len == 4);
00774 
00775   root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
00776 
00777   if (drop && root_page_no == FIL_NULL) {
00778     /* The tree has been freed. */
00779 
00780     ut_print_timestamp(stderr);
00781     fprintf(stderr, "  InnoDB: Trying to TRUNCATE"
00782       " a missing index of table %s!\n", table->name);
00783     drop = FALSE;
00784   }
00785 
00786   ptr = rec_get_nth_field_old(rec,
00787             DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
00788 
00789   ut_ad(len == 4);
00790 
00791   if (drop) {
00792     space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
00793   }
00794 
00795   zip_size = fil_space_get_zip_size(space);
00796 
00797   if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
00798     /* It is a single table tablespace and the .ibd file is
00799     missing: do nothing */
00800 
00801     ut_print_timestamp(stderr);
00802     fprintf(stderr, "  InnoDB: Trying to TRUNCATE"
00803       " a missing .ibd file of table %s!\n", table->name);
00804     return(FIL_NULL);
00805   }
00806 
00807   ptr = rec_get_nth_field_old(rec,
00808             DICT_SYS_INDEXES_TYPE_FIELD, &len);
00809   ut_ad(len == 4);
00810   type = mach_read_from_4(ptr);
00811 
00812   ptr = rec_get_nth_field_old(rec, 1, &len);
00813   ut_ad(len == 8);
00814   index_id = mach_read_from_8(ptr);
00815 
00816   if (!drop) {
00817 
00818     goto create;
00819   }
00820 
00821   /* We free all the pages but the root page first; this operation
00822   may span several mini-transactions */
00823 
00824   btr_free_but_not_root(space, zip_size, root_page_no);
00825 
00826   /* Then we free the root page in the same mini-transaction where
00827   we create the b-tree and write its new root page number to the
00828   appropriate field in the SYS_INDEXES record: this mini-transaction
00829   marks the B-tree totally truncated */
00830 
00831   btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
00832 
00833   btr_free_root(space, zip_size, root_page_no, mtr);
00834 create:
00835   /* We will temporarily write FIL_NULL to the PAGE_NO field
00836   in SYS_INDEXES, so that the database will not get into an
00837   inconsistent state in case it crashes between the mtr_commit()
00838   below and the following mtr_commit() call. */
00839   page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
00840              FIL_NULL, mtr);
00841 
00842   /* We will need to commit the mini-transaction in order to avoid
00843   deadlocks in the btr_create() call, because otherwise we would
00844   be freeing and allocating pages in the same mini-transaction. */
00845   btr_pcur_store_position(pcur, mtr);
00846   mtr_commit(mtr);
00847 
00848   mtr_start(mtr);
00849   btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
00850 
00851   /* Find the index corresponding to this SYS_INDEXES record. */
00852   for (index = UT_LIST_GET_FIRST(table->indexes);
00853        index;
00854        index = UT_LIST_GET_NEXT(indexes, index)) {
00855     if (index->id == index_id) {
00856       root_page_no = btr_create(type, space, zip_size,
00857               index_id, index, mtr);
00858       index->page = (unsigned int) root_page_no;
00859       return(root_page_no);
00860     }
00861   }
00862 
00863   ut_print_timestamp(stderr);
00864   fprintf(stderr,
00865     "  InnoDB: Index %llu of table %s is missing\n"
00866     "InnoDB: from the data dictionary during TRUNCATE!\n",
00867     (ullint) index_id,
00868     table->name);
00869 
00870   return(FIL_NULL);
00871 }
00872 
00873 /*********************************************************************/
00876 UNIV_INTERN
00877 tab_node_t*
00878 tab_create_graph_create(
00879 /*====================*/
00880   dict_table_t* table,  
00882   mem_heap_t* heap) 
00883 {
00884   tab_node_t* node;
00885 
00886   node = static_cast<tab_node_t *>(mem_heap_alloc(heap, sizeof(tab_node_t)));
00887 
00888   node->common.type = QUE_NODE_CREATE_TABLE;
00889 
00890   node->table = table;
00891 
00892   node->state = TABLE_BUILD_TABLE_DEF;
00893   node->heap = mem_heap_create(256);
00894 
00895   node->tab_def = ins_node_create(INS_DIRECT, dict_sys->sys_tables,
00896           heap);
00897   node->tab_def->common.parent = node;
00898 
00899   node->col_def = ins_node_create(INS_DIRECT, dict_sys->sys_columns,
00900           heap);
00901   node->col_def->common.parent = node;
00902 
00903   node->commit_node = commit_node_create(heap);
00904   node->commit_node->common.parent = node;
00905 
00906   return(node);
00907 }
00908 
00909 /*********************************************************************/
00912 UNIV_INTERN
00913 ind_node_t*
00914 ind_create_graph_create(
00915 /*====================*/
00916   dict_index_t* index,  
00918   mem_heap_t* heap) 
00919 {
00920   ind_node_t* node;
00921 
00922   node = static_cast<ind_node_t *>(mem_heap_alloc(heap, sizeof(ind_node_t)));
00923 
00924   node->common.type = QUE_NODE_CREATE_INDEX;
00925 
00926   node->index = index;
00927 
00928   node->state = INDEX_BUILD_INDEX_DEF;
00929   node->page_no = FIL_NULL;
00930   node->heap = mem_heap_create(256);
00931 
00932   node->ind_def = ins_node_create(INS_DIRECT,
00933           dict_sys->sys_indexes, heap);
00934   node->ind_def->common.parent = node;
00935 
00936   node->field_def = ins_node_create(INS_DIRECT,
00937             dict_sys->sys_fields, heap);
00938   node->field_def->common.parent = node;
00939 
00940   node->commit_node = commit_node_create(heap);
00941   node->commit_node->common.parent = node;
00942 
00943   return(node);
00944 }
00945 
00946 /***********************************************************/
00949 UNIV_INTERN
00950 que_thr_t*
00951 dict_create_table_step(
00952 /*===================*/
00953   que_thr_t*  thr)  
00954 {
00955   tab_node_t* node;
00956   ulint   err = DB_ERROR;
00957   trx_t*    trx;
00958 
00959   ut_ad(thr);
00960   ut_ad(mutex_own(&(dict_sys->mutex)));
00961 
00962   trx = thr_get_trx(thr);
00963 
00964   node = static_cast<tab_node_t *>(thr->run_node);
00965 
00966   ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_TABLE);
00967 
00968   if (thr->prev_node == que_node_get_parent(node)) {
00969     node->state = TABLE_BUILD_TABLE_DEF;
00970   }
00971 
00972   if (node->state == TABLE_BUILD_TABLE_DEF) {
00973 
00974     /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
00975 
00976     err = dict_build_table_def_step(thr, node);
00977 
00978     if (err != DB_SUCCESS) {
00979 
00980       goto function_exit;
00981     }
00982 
00983     node->state = TABLE_BUILD_COL_DEF;
00984     node->col_no = 0;
00985 
00986     thr->run_node = node->tab_def;
00987 
00988     return(thr);
00989   }
00990 
00991   if (node->state == TABLE_BUILD_COL_DEF) {
00992 
00993     if (node->col_no < (node->table)->n_def) {
00994 
00995       err = dict_build_col_def_step(node);
00996 
00997       if (err != DB_SUCCESS) {
00998 
00999         goto function_exit;
01000       }
01001 
01002       node->col_no++;
01003 
01004       thr->run_node = node->col_def;
01005 
01006       return(thr);
01007     } else {
01008       node->state = TABLE_COMMIT_WORK;
01009     }
01010   }
01011 
01012   if (node->state == TABLE_COMMIT_WORK) {
01013 
01014     /* Table was correctly defined: do NOT commit the transaction
01015     (CREATE TABLE does NOT do an implicit commit of the current
01016     transaction) */
01017 
01018     node->state = TABLE_ADD_TO_CACHE;
01019 
01020     /* thr->run_node = node->commit_node;
01021 
01022     return(thr); */
01023   }
01024 
01025   if (node->state == TABLE_ADD_TO_CACHE) {
01026 
01027     dict_table_add_to_cache(node->table, node->heap);
01028 
01029     err = DB_SUCCESS;
01030   }
01031 
01032 function_exit:
01033   trx->error_state = err;
01034 
01035   if (err == DB_SUCCESS) {
01036     /* Ok: do nothing */
01037 
01038   } else if (err == DB_LOCK_WAIT) {
01039 
01040     return(NULL);
01041   } else {
01042     /* SQL error detected */
01043 
01044     return(NULL);
01045   }
01046 
01047   thr->run_node = que_node_get_parent(node);
01048 
01049   return(thr);
01050 }
01051 
01052 /***********************************************************/
01056 UNIV_INTERN
01057 que_thr_t*
01058 dict_create_index_step(
01059 /*===================*/
01060   que_thr_t*  thr)  
01061 {
01062   ind_node_t* node;
01063   ulint   err = DB_ERROR;
01064   trx_t*    trx;
01065 
01066   ut_ad(thr);
01067   ut_ad(mutex_own(&(dict_sys->mutex)));
01068 
01069   trx = thr_get_trx(thr);
01070 
01071   node = static_cast<ind_node_t *>(thr->run_node);
01072 
01073   ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_INDEX);
01074 
01075   if (thr->prev_node == que_node_get_parent(node)) {
01076     node->state = INDEX_BUILD_INDEX_DEF;
01077   }
01078 
01079   if (node->state == INDEX_BUILD_INDEX_DEF) {
01080     /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
01081     err = dict_build_index_def_step(thr, node);
01082 
01083     if (err != DB_SUCCESS) {
01084 
01085       goto function_exit;
01086     }
01087 
01088     node->state = INDEX_BUILD_FIELD_DEF;
01089     node->field_no = 0;
01090 
01091     thr->run_node = node->ind_def;
01092 
01093     return(thr);
01094   }
01095 
01096   if (node->state == INDEX_BUILD_FIELD_DEF) {
01097 
01098     if (node->field_no < (node->index)->n_fields) {
01099 
01100       err = dict_build_field_def_step(node);
01101 
01102       if (err != DB_SUCCESS) {
01103 
01104         goto function_exit;
01105       }
01106 
01107       node->field_no++;
01108 
01109       thr->run_node = node->field_def;
01110 
01111       return(thr);
01112     } else {
01113       node->state = INDEX_ADD_TO_CACHE;
01114     }
01115   }
01116 
01117   if (node->state == INDEX_ADD_TO_CACHE) {
01118 
01119     index_id_t  index_id = node->index->id;
01120 
01121     err = dict_index_add_to_cache(
01122       node->table, node->index, FIL_NULL,
01123       trx_is_strict(trx)
01124       || dict_table_get_format(node->table)
01125       >= DICT_TF_FORMAT_ZIP);
01126 
01127     node->index = dict_index_get_if_in_cache_low(index_id);
01128     ut_a(!node->index == (err != DB_SUCCESS));
01129 
01130     if (err != DB_SUCCESS) {
01131 
01132       goto function_exit;
01133     }
01134 
01135     node->state = INDEX_CREATE_INDEX_TREE;
01136   }
01137 
01138   if (node->state == INDEX_CREATE_INDEX_TREE) {
01139 
01140     err = dict_create_index_tree_step(node);
01141 
01142     if (err != DB_SUCCESS) {
01143       dict_index_remove_from_cache(node->table, node->index);
01144       node->index = NULL;
01145 
01146       goto function_exit;
01147     }
01148 
01149     node->index->page = node->page_no;
01150     node->state = INDEX_COMMIT_WORK;
01151   }
01152 
01153   if (node->state == INDEX_COMMIT_WORK) {
01154 
01155     /* Index was correctly defined: do NOT commit the transaction
01156     (CREATE INDEX does NOT currently do an implicit commit of
01157     the current transaction) */
01158 
01159     node->state = INDEX_CREATE_INDEX_TREE;
01160 
01161     /* thr->run_node = node->commit_node;
01162 
01163     return(thr); */
01164   }
01165 
01166 function_exit:
01167   trx->error_state = err;
01168 
01169   if (err == DB_SUCCESS) {
01170     /* Ok: do nothing */
01171 
01172   } else if (err == DB_LOCK_WAIT) {
01173 
01174     return(NULL);
01175   } else {
01176     /* SQL error detected */
01177 
01178     return(NULL);
01179   }
01180 
01181   thr->run_node = que_node_get_parent(node);
01182 
01183   return(thr);
01184 }
01185 
01186 /****************************************************************/
01191 UNIV_INTERN
01192 ulint
01193 dict_create_or_check_foreign_constraint_tables(void)
01194 /*================================================*/
01195 {
01196   dict_table_t* table1;
01197   dict_table_t* table2;
01198   ulint   error;
01199   trx_t*    trx;
01200 
01201   mutex_enter(&(dict_sys->mutex));
01202 
01203   table1 = dict_table_get_low("SYS_FOREIGN");
01204   table2 = dict_table_get_low("SYS_FOREIGN_COLS");
01205 
01206   if (table1 && table2
01207       && UT_LIST_GET_LEN(table1->indexes) == 3
01208       && UT_LIST_GET_LEN(table2->indexes) == 1) {
01209 
01210     /* Foreign constraint system tables have already been
01211     created, and they are ok */
01212 
01213     mutex_exit(&(dict_sys->mutex));
01214 
01215     return(DB_SUCCESS);
01216   }
01217 
01218   mutex_exit(&(dict_sys->mutex));
01219 
01220   trx = trx_allocate_for_mysql();
01221 
01222   trx->op_info = "creating foreign key sys tables";
01223 
01224   row_mysql_lock_data_dictionary(trx);
01225 
01226   if (table1) {
01227     fprintf(stderr,
01228       "InnoDB: dropping incompletely created"
01229       " SYS_FOREIGN table\n");
01230     row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
01231   }
01232 
01233   if (table2) {
01234     fprintf(stderr,
01235       "InnoDB: dropping incompletely created"
01236       " SYS_FOREIGN_COLS table\n");
01237     row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
01238   }
01239 
01240   fprintf(stderr,
01241     "InnoDB: Creating foreign key constraint system tables\n");
01242 
01243   /* NOTE: in dict_load_foreigns we use the fact that
01244   there are 2 secondary indexes on SYS_FOREIGN, and they
01245   are defined just like below */
01246 
01247   /* NOTE: when designing InnoDB's foreign key support in 2001, we made
01248   an error and made the table names and the foreign key id of type
01249   'CHAR' (internally, really a VARCHAR). We should have made the type
01250   VARBINARY, like in other InnoDB system tables, to get a clean
01251   design. */
01252 
01253         pars_info_t *info = pars_info_create();
01254   error = que_eval_sql(info,
01255            "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
01256            "BEGIN\n"
01257            "CREATE TABLE\n"
01258            "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
01259            " REF_NAME CHAR, N_COLS INT);\n"
01260            "CREATE UNIQUE CLUSTERED INDEX ID_IND"
01261            " ON SYS_FOREIGN (ID);\n"
01262            "CREATE INDEX FOR_IND"
01263            " ON SYS_FOREIGN (FOR_NAME);\n"
01264            "CREATE INDEX REF_IND"
01265            " ON SYS_FOREIGN (REF_NAME);\n"
01266            "CREATE TABLE\n"
01267            "SYS_FOREIGN_COLS(ID CHAR, POS INT,"
01268            " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
01269            "CREATE UNIQUE CLUSTERED INDEX ID_IND"
01270            " ON SYS_FOREIGN_COLS (ID, POS);\n"
01271            "END;\n"
01272            , FALSE, trx);
01273 
01274   if (error != DB_SUCCESS) {
01275     fprintf(stderr, "InnoDB: error %lu in creation\n",
01276       (ulong) error);
01277 
01278     ut_a(error == DB_OUT_OF_FILE_SPACE
01279          || error == DB_TOO_MANY_CONCURRENT_TRXS);
01280 
01281     fprintf(stderr,
01282       "InnoDB: creation failed\n"
01283       "InnoDB: tablespace is full\n"
01284       "InnoDB: dropping incompletely created"
01285       " SYS_FOREIGN tables\n");
01286 
01287     row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
01288     row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
01289 
01290     error = DB_MUST_GET_MORE_FILE_SPACE;
01291   }
01292 
01293   trx_commit_for_mysql(trx);
01294 
01295   row_mysql_unlock_data_dictionary(trx);
01296 
01297   trx_free_for_mysql(trx);
01298 
01299   if (error == DB_SUCCESS) {
01300     fprintf(stderr,
01301       "InnoDB: Foreign key constraint system tables"
01302       " created\n");
01303   }
01304 
01305   return(error);
01306 }
01307 
01308 /****************************************************************/
01311 static
01312 ulint
01313 dict_foreign_eval_sql(
01314 /*==================*/
01315   pars_info_t*  info, 
01316   const char* sql,  
01317   dict_table_t* table,  
01318   dict_foreign_t* foreign,
01319   trx_t*    trx)  
01320 {
01321   ulint   error;
01322   FILE*   ef  = dict_foreign_err_file;
01323 
01324   error = que_eval_sql(info, sql, FALSE, trx);
01325 
01326   if (error == DB_DUPLICATE_KEY) {
01327     mutex_enter(&dict_foreign_err_mutex);
01328     rewind(ef);
01329     ut_print_timestamp(ef);
01330     fputs(" Error in foreign key constraint creation for table ",
01331           ef);
01332     ut_print_name(ef, trx, TRUE, table->name);
01333     fputs(".\nA foreign key constraint of name ", ef);
01334     ut_print_name(ef, trx, TRUE, foreign->id);
01335     fputs("\nalready exists."
01336           " (Note that internally InnoDB adds 'databasename'\n"
01337           "in front of the user-defined constraint name.)\n"
01338           "Note that InnoDB's FOREIGN KEY system tables store\n"
01339           "constraint names as case-insensitive, with the\n"
01340           "MySQL standard latin1_swedish_ci collation. If you\n"
01341           "create tables or databases whose names differ only in\n"
01342           "the character case, then collisions in constraint\n"
01343           "names can occur. Workaround: name your constraints\n"
01344           "explicitly with unique names.\n",
01345           ef);
01346 
01347     mutex_exit(&dict_foreign_err_mutex);
01348 
01349     return(error);
01350   }
01351 
01352   if (error != DB_SUCCESS) {
01353     fprintf(stderr,
01354       "InnoDB: Foreign key constraint creation failed:\n"
01355       "InnoDB: internal error number %lu\n", (ulong) error);
01356 
01357     mutex_enter(&dict_foreign_err_mutex);
01358     ut_print_timestamp(ef);
01359     fputs(" Internal error in foreign key constraint creation"
01360           " for table ", ef);
01361     ut_print_name(ef, trx, TRUE, table->name);
01362     fputs(".\n"
01363           "See the MySQL .err log in the datadir"
01364           " for more information.\n", ef);
01365     mutex_exit(&dict_foreign_err_mutex);
01366 
01367     return(error);
01368   }
01369 
01370   return(DB_SUCCESS);
01371 }
01372 
01373 /********************************************************************/
01377 static
01378 ulint
01379 dict_create_add_foreign_field_to_dictionary(
01380 /*========================================*/
01381   ulint   field_nr, 
01382   dict_table_t* table,    
01383   dict_foreign_t* foreign,  
01384   trx_t*    trx)    
01385 {
01386   pars_info_t*  info = pars_info_create();
01387 
01388   pars_info_add_str_literal(info, "id", foreign->id);
01389 
01390   pars_info_add_int4_literal(info, "pos", field_nr);
01391 
01392   pars_info_add_str_literal(info, "for_col_name",
01393           foreign->foreign_col_names[field_nr]);
01394 
01395   pars_info_add_str_literal(info, "ref_col_name",
01396           foreign->referenced_col_names[field_nr]);
01397 
01398   return(dict_foreign_eval_sql(
01399            info,
01400            "PROCEDURE P () IS\n"
01401            "BEGIN\n"
01402            "INSERT INTO SYS_FOREIGN_COLS VALUES"
01403            "(:id, :pos, :for_col_name, :ref_col_name);\n"
01404            "END;\n",
01405            table, foreign, trx));
01406 }
01407 
01408 /********************************************************************/
01416 static
01417 ulint
01418 dict_create_add_foreign_to_dictionary(
01419 /*==================================*/
01420   ulint*    id_nr,  
01422   dict_table_t* table,  
01423   dict_foreign_t* foreign,
01424   trx_t*    trx)  
01425 {
01426   ulint   error;
01427   ulint   i;
01428 
01429   pars_info_t*  info = pars_info_create();
01430 
01431   if (foreign->id == NULL) {
01432     /* Generate a new constraint id */
01433     ulint namelen = strlen(table->name);
01434     char* id  = static_cast<char *>(mem_heap_alloc(foreign->heap, namelen + 20));
01435     /* no overflow if number < 1e13 */
01436     sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++);
01437     foreign->id = id;
01438   }
01439 
01440   pars_info_add_str_literal(info, "id", foreign->id);
01441 
01442   pars_info_add_str_literal(info, "for_name", table->name);
01443 
01444   pars_info_add_str_literal(info, "ref_name",
01445           foreign->referenced_table_name);
01446 
01447   pars_info_add_int4_literal(info, "n_cols",
01448            foreign->n_fields + (foreign->type << 24));
01449 
01450   error = dict_foreign_eval_sql(info,
01451               "PROCEDURE P () IS\n"
01452               "BEGIN\n"
01453               "INSERT INTO SYS_FOREIGN VALUES"
01454               "(:id, :for_name, :ref_name, :n_cols);\n"
01455               "END;\n"
01456               , table, foreign, trx);
01457 
01458   if (error != DB_SUCCESS) {
01459 
01460     return(error);
01461   }
01462 
01463   for (i = 0; i < foreign->n_fields; i++) {
01464     error = dict_create_add_foreign_field_to_dictionary(
01465       i, table, foreign, trx);
01466 
01467     if (error != DB_SUCCESS) {
01468 
01469       return(error);
01470     }
01471   }
01472 
01473   error = dict_foreign_eval_sql(NULL,
01474               "PROCEDURE P () IS\n"
01475               "BEGIN\n"
01476               "COMMIT WORK;\n"
01477               "END;\n"
01478               , table, foreign, trx);
01479 
01480   return(error);
01481 }
01482 
01483 /********************************************************************/
01486 UNIV_INTERN
01487 ulint
01488 dict_create_add_foreigns_to_dictionary(
01489 /*===================================*/
01490   ulint   start_id,
01498   dict_table_t* table,  
01499   trx_t*    trx)  
01500 {
01501   dict_foreign_t* foreign;
01502   ulint   number  = start_id + 1;
01503   ulint   error;
01504 
01505   ut_ad(mutex_own(&(dict_sys->mutex)));
01506 
01507   if (NULL == dict_table_get_low("SYS_FOREIGN")) {
01508     fprintf(stderr,
01509       "InnoDB: table SYS_FOREIGN not found"
01510       " in internal data dictionary\n");
01511 
01512     return(DB_ERROR);
01513   }
01514 
01515   for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
01516        foreign;
01517        foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
01518 
01519     error = dict_create_add_foreign_to_dictionary(&number, table,
01520                     foreign, trx);
01521 
01522     if (error != DB_SUCCESS) {
01523 
01524       return(error);
01525     }
01526   }
01527 
01528   return(DB_SUCCESS);
01529 }