diff options
Diffstat (limited to 'storage/innobase/dict/dict0crea.c')
-rw-r--r-- | storage/innobase/dict/dict0crea.c | 1450 |
1 files changed, 0 insertions, 1450 deletions
diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c deleted file mode 100644 index 4116230347d..00000000000 --- a/storage/innobase/dict/dict0crea.c +++ /dev/null @@ -1,1450 +0,0 @@ -/****************************************************** -Database object creation - -(c) 1996 Innobase Oy - -Created 1/8/1996 Heikki Tuuri -*******************************************************/ - -#include "dict0crea.h" - -#ifdef UNIV_NONINL -#include "dict0crea.ic" -#endif - -#include "btr0pcur.h" -#include "btr0btr.h" -#include "page0page.h" -#include "mach0data.h" -#include "dict0boot.h" -#include "dict0dict.h" -#include "que0que.h" -#include "row0ins.h" -#include "row0mysql.h" -#include "pars0pars.h" -#include "trx0roll.h" -#include "usr0sess.h" -#include "ut0vec.h" - -/********************************************************************* -Based on a table object, this function builds the entry to be inserted -in the SYS_TABLES system table. */ -static -dtuple_t* -dict_create_sys_tables_tuple( -/*=========================*/ - /* out: the tuple which should be inserted */ - dict_table_t* table, /* in: table */ - mem_heap_t* heap) /* in: memory heap from which the memory for - the built tuple is allocated */ -{ - dict_table_t* sys_tables; - dtuple_t* entry; - dfield_t* dfield; - byte* ptr; - - ut_ad(table && heap); - - sys_tables = dict_sys->sys_tables; - - entry = dtuple_create(heap, 8 + DATA_N_SYS_COLS); - - /* 0: NAME -----------------------------*/ - dfield = dtuple_get_nth_field(entry, 0); - - dfield_set_data(dfield, table->name, ut_strlen(table->name)); - /* 3: ID -------------------------------*/ - dfield = dtuple_get_nth_field(entry, 1); - - ptr = mem_heap_alloc(heap, 8); - mach_write_to_8(ptr, table->id); - - dfield_set_data(dfield, ptr, 8); - /* 4: N_COLS ---------------------------*/ - dfield = dtuple_get_nth_field(entry, 2); - -#if DICT_TF_COMPACT != 1 -#error -#endif - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, table->n_def - | ((table->flags & DICT_TF_COMPACT) << 31)); - dfield_set_data(dfield, ptr, 4); - /* 5: TYPE -----------------------------*/ - dfield = dtuple_get_nth_field(entry, 3); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, DICT_TABLE_ORDINARY); - - dfield_set_data(dfield, ptr, 4); - /* 6: MIX_ID (obsolete) ---------------------------*/ - dfield = dtuple_get_nth_field(entry, 4); - - ptr = mem_heap_alloc(heap, 8); - memset(ptr, 0, 8); - - dfield_set_data(dfield, ptr, 8); - /* 7: MIX_LEN (obsolete) --------------------------*/ - - dfield = dtuple_get_nth_field(entry, 5); - - ptr = mem_heap_alloc(heap, 4); - memset(ptr, 0, 4); - - dfield_set_data(dfield, ptr, 4); - /* 8: CLUSTER_NAME ---------------------*/ - dfield = dtuple_get_nth_field(entry, 6); - dfield_set_data(dfield, NULL, UNIV_SQL_NULL); /* not supported */ - - /* 9: SPACE ----------------------------*/ - dfield = dtuple_get_nth_field(entry, 7); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, table->space); - - dfield_set_data(dfield, ptr, 4); - /*----------------------------------*/ - - dict_table_copy_types(entry, sys_tables); - - return(entry); -} - -/********************************************************************* -Based on a table object, this function builds the entry to be inserted -in the SYS_COLUMNS system table. */ -static -dtuple_t* -dict_create_sys_columns_tuple( -/*==========================*/ - /* out: the tuple which should be inserted */ - dict_table_t* table, /* in: table */ - ulint i, /* in: column number */ - mem_heap_t* heap) /* in: memory heap from which the memory for - the built tuple is allocated */ -{ - dict_table_t* sys_columns; - dtuple_t* entry; - const dict_col_t* column; - dfield_t* dfield; - byte* ptr; - const char* col_name; - - ut_ad(table && heap); - - column = dict_table_get_nth_col(table, i); - - sys_columns = dict_sys->sys_columns; - - entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS); - - /* 0: TABLE_ID -----------------------*/ - dfield = dtuple_get_nth_field(entry, 0); - - ptr = mem_heap_alloc(heap, 8); - mach_write_to_8(ptr, table->id); - - dfield_set_data(dfield, ptr, 8); - /* 1: POS ----------------------------*/ - dfield = dtuple_get_nth_field(entry, 1); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, i); - - dfield_set_data(dfield, ptr, 4); - /* 4: NAME ---------------------------*/ - dfield = dtuple_get_nth_field(entry, 2); - - col_name = dict_table_get_col_name(table, i); - dfield_set_data(dfield, col_name, ut_strlen(col_name)); - /* 5: MTYPE --------------------------*/ - dfield = dtuple_get_nth_field(entry, 3); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, column->mtype); - - dfield_set_data(dfield, ptr, 4); - /* 6: PRTYPE -------------------------*/ - dfield = dtuple_get_nth_field(entry, 4); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, column->prtype); - - dfield_set_data(dfield, ptr, 4); - /* 7: LEN ----------------------------*/ - dfield = dtuple_get_nth_field(entry, 5); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, column->len); - - dfield_set_data(dfield, ptr, 4); - /* 8: PREC ---------------------------*/ - dfield = dtuple_get_nth_field(entry, 6); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, 0/* unused */); - - dfield_set_data(dfield, ptr, 4); - /*---------------------------------*/ - - dict_table_copy_types(entry, sys_columns); - - return(entry); -} - -/******************************************************************* -Builds a table definition to insert. */ -static -ulint -dict_build_table_def_step( -/*======================*/ - /* out: DB_SUCCESS or error code */ - que_thr_t* thr, /* in: query thread */ - tab_node_t* node) /* in: table create node */ -{ - dict_table_t* table; - dtuple_t* row; - ulint error; - const char* path_or_name; - ibool is_path; - mtr_t mtr; - ulint i; - ulint row_len; - - ut_ad(mutex_own(&(dict_sys->mutex))); - - table = node->table; - - table->id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); - - thr_get_trx(thr)->table_id = table->id; - - row_len = 0; - for (i = 0; i < table->n_def; i++) { - row_len += dict_col_get_min_size(&table->cols[i]); - } - if (row_len > BTR_PAGE_MAX_REC_SIZE) { - return(DB_TOO_BIG_RECORD); - } - - if (srv_file_per_table) { - /* We create a new single-table tablespace for the table. - We initially let it be 4 pages: - - page 0 is the fsp header and an extent descriptor page, - - page 1 is an ibuf bitmap page, - - page 2 is the first inode page, - - page 3 will contain the root of the clustered index of the - table we create here. */ - - ulint space = 0; /* reset to zero for the call below */ - - if (table->dir_path_of_temp_table) { - /* We place tables created with CREATE TEMPORARY - TABLE in the tmp dir of mysqld server */ - - path_or_name = table->dir_path_of_temp_table; - is_path = TRUE; - } else { - path_or_name = table->name; - is_path = FALSE; - } - - error = fil_create_new_single_table_tablespace( - &space, path_or_name, is_path, - FIL_IBD_FILE_INITIAL_SIZE); - table->space = (unsigned int) space; - - if (error != DB_SUCCESS) { - - return(error); - } - - mtr_start(&mtr); - - fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr); - - mtr_commit(&mtr); - } - - row = dict_create_sys_tables_tuple(table, node->heap); - - ins_node_set_new_row(node->tab_def, row); - - return(DB_SUCCESS); -} - -/******************************************************************* -Builds a column definition to insert. */ -static -ulint -dict_build_col_def_step( -/*====================*/ - /* out: DB_SUCCESS */ - tab_node_t* node) /* in: table create node */ -{ - dtuple_t* row; - - row = dict_create_sys_columns_tuple(node->table, node->col_no, - node->heap); - ins_node_set_new_row(node->col_def, row); - - return(DB_SUCCESS); -} - -/********************************************************************* -Based on an index object, this function builds the entry to be inserted -in the SYS_INDEXES system table. */ -static -dtuple_t* -dict_create_sys_indexes_tuple( -/*==========================*/ - /* out: the tuple which should be inserted */ - dict_index_t* index, /* in: index */ - mem_heap_t* heap) /* in: memory heap from which the memory for - the built tuple is allocated */ -{ - dict_table_t* sys_indexes; - dict_table_t* table; - dtuple_t* entry; - dfield_t* dfield; - byte* ptr; - - ut_ad(mutex_own(&(dict_sys->mutex))); - ut_ad(index && heap); - - sys_indexes = dict_sys->sys_indexes; - - table = dict_table_get_low(index->table_name); - - entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS); - - /* 0: TABLE_ID -----------------------*/ - dfield = dtuple_get_nth_field(entry, 0); - - ptr = mem_heap_alloc(heap, 8); - mach_write_to_8(ptr, table->id); - - dfield_set_data(dfield, ptr, 8); - /* 1: ID ----------------------------*/ - dfield = dtuple_get_nth_field(entry, 1); - - ptr = mem_heap_alloc(heap, 8); - mach_write_to_8(ptr, index->id); - - dfield_set_data(dfield, ptr, 8); - /* 4: NAME --------------------------*/ - dfield = dtuple_get_nth_field(entry, 2); - - dfield_set_data(dfield, index->name, ut_strlen(index->name)); - /* 5: N_FIELDS ----------------------*/ - dfield = dtuple_get_nth_field(entry, 3); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, index->n_fields); - - dfield_set_data(dfield, ptr, 4); - /* 6: TYPE --------------------------*/ - dfield = dtuple_get_nth_field(entry, 4); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, index->type); - - dfield_set_data(dfield, ptr, 4); - /* 7: SPACE --------------------------*/ - -#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 7 -#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 7" -#endif - - dfield = dtuple_get_nth_field(entry, 5); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, index->space); - - dfield_set_data(dfield, ptr, 4); - /* 8: PAGE_NO --------------------------*/ - -#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 8 -#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 8" -#endif - - dfield = dtuple_get_nth_field(entry, 6); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, FIL_NULL); - - dfield_set_data(dfield, ptr, 4); - /*--------------------------------*/ - - dict_table_copy_types(entry, sys_indexes); - - return(entry); -} - -/********************************************************************* -Based on an index object, this function builds the entry to be inserted -in the SYS_FIELDS system table. */ -static -dtuple_t* -dict_create_sys_fields_tuple( -/*=========================*/ - /* out: the tuple which should be inserted */ - dict_index_t* index, /* in: index */ - ulint i, /* in: field number */ - mem_heap_t* heap) /* in: memory heap from which the memory for - the built tuple is allocated */ -{ - dict_table_t* sys_fields; - dtuple_t* entry; - dict_field_t* field; - dfield_t* dfield; - byte* ptr; - ibool index_contains_column_prefix_field = FALSE; - ulint j; - - ut_ad(index && heap); - - for (j = 0; j < index->n_fields; j++) { - if (dict_index_get_nth_field(index, j)->prefix_len > 0) { - index_contains_column_prefix_field = TRUE; - } - } - - field = dict_index_get_nth_field(index, i); - - sys_fields = dict_sys->sys_fields; - - entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS); - - /* 0: INDEX_ID -----------------------*/ - dfield = dtuple_get_nth_field(entry, 0); - - ptr = mem_heap_alloc(heap, 8); - mach_write_to_8(ptr, index->id); - - dfield_set_data(dfield, ptr, 8); - /* 1: POS + PREFIX LENGTH ----------------------------*/ - - dfield = dtuple_get_nth_field(entry, 1); - - ptr = mem_heap_alloc(heap, 4); - - if (index_contains_column_prefix_field) { - /* If there are column prefix fields in the index, then - we store the number of the field to the 2 HIGH bytes - and the prefix length to the 2 low bytes, */ - - mach_write_to_4(ptr, (i << 16) + field->prefix_len); - } else { - /* Else we store the number of the field to the 2 LOW bytes. - This is to keep the storage format compatible with - InnoDB versions < 4.0.14. */ - - mach_write_to_4(ptr, i); - } - - dfield_set_data(dfield, ptr, 4); - /* 4: COL_NAME -------------------------*/ - dfield = dtuple_get_nth_field(entry, 2); - - dfield_set_data(dfield, field->name, - ut_strlen(field->name)); - /*---------------------------------*/ - - dict_table_copy_types(entry, sys_fields); - - return(entry); -} - -/********************************************************************* -Creates the tuple with which the index entry is searched for writing the index -tree root page number, if such a tree is created. */ -static -dtuple_t* -dict_create_search_tuple( -/*=====================*/ - /* out: the tuple for search */ - dtuple_t* tuple, /* in: the tuple inserted in the SYS_INDEXES - table */ - mem_heap_t* heap) /* in: memory heap from which the memory for - the built tuple is allocated */ -{ - dtuple_t* search_tuple; - dfield_t* field1; - dfield_t* field2; - - ut_ad(tuple && heap); - - search_tuple = dtuple_create(heap, 2); - - field1 = dtuple_get_nth_field(tuple, 0); - field2 = dtuple_get_nth_field(search_tuple, 0); - - dfield_copy(field2, field1); - - field1 = dtuple_get_nth_field(tuple, 1); - field2 = dtuple_get_nth_field(search_tuple, 1); - - dfield_copy(field2, field1); - - ut_ad(dtuple_validate(search_tuple)); - - return(search_tuple); -} - -/******************************************************************* -Builds an index definition row to insert. */ -static -ulint -dict_build_index_def_step( -/*======================*/ - /* out: DB_SUCCESS or error code */ - que_thr_t* thr, /* in: query thread */ - ind_node_t* node) /* in: index create node */ -{ - dict_table_t* table; - dict_index_t* index; - dtuple_t* row; - trx_t* trx; - - ut_ad(mutex_own(&(dict_sys->mutex))); - - trx = thr_get_trx(thr); - - index = node->index; - - table = dict_table_get_low(index->table_name); - - if (table == NULL) { - return(DB_TABLE_NOT_FOUND); - } - - trx->table_id = table->id; - - node->table = table; - - ut_ad((UT_LIST_GET_LEN(table->indexes) > 0) - || (index->type & DICT_CLUSTERED)); - - index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID); - - /* Inherit the space id from the table; we store all indexes of a - table in the same tablespace */ - - index->space = table->space; - node->page_no = FIL_NULL; - row = dict_create_sys_indexes_tuple(index, node->heap); - node->ind_row = row; - - ins_node_set_new_row(node->ind_def, row); - - return(DB_SUCCESS); -} - -/******************************************************************* -Builds a field definition row to insert. */ -static -ulint -dict_build_field_def_step( -/*======================*/ - /* out: DB_SUCCESS */ - ind_node_t* node) /* in: index create node */ -{ - dict_index_t* index; - dtuple_t* row; - - index = node->index; - - row = dict_create_sys_fields_tuple(index, node->field_no, node->heap); - - ins_node_set_new_row(node->field_def, row); - - return(DB_SUCCESS); -} - -/******************************************************************* -Creates an index tree for the index if it is not a member of a cluster. */ -static -ulint -dict_create_index_tree_step( -/*========================*/ - /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ - ind_node_t* node) /* in: index create node */ -{ - dict_index_t* index; - dict_table_t* sys_indexes; - dict_table_t* table; - dtuple_t* search_tuple; - btr_pcur_t pcur; - mtr_t mtr; - - ut_ad(mutex_own(&(dict_sys->mutex))); - - index = node->index; - table = node->table; - - sys_indexes = dict_sys->sys_indexes; - - /* Run a mini-transaction in which the index tree is allocated for - the index and its root address is written to the index entry in - sys_indexes */ - - mtr_start(&mtr); - - search_tuple = dict_create_search_tuple(node->ind_row, node->heap); - - btr_pcur_open(UT_LIST_GET_FIRST(sys_indexes->indexes), - search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF, - &pcur, &mtr); - - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - - node->page_no = btr_create(index->type, index->space, index->id, - dict_table_is_comp(table), &mtr); - /* printf("Created a new index tree in space %lu root page %lu\n", - index->space, index->page_no); */ - - page_rec_write_index_page_no(btr_pcur_get_rec(&pcur), - DICT_SYS_INDEXES_PAGE_NO_FIELD, - node->page_no, &mtr); - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - if (node->page_no == FIL_NULL) { - - return(DB_OUT_OF_FILE_SPACE); - } - - return(DB_SUCCESS); -} - -/*********************************************************************** -Drops the index tree associated with a row in SYS_INDEXES table. */ - -void -dict_drop_index_tree( -/*=================*/ - rec_t* rec, /* in: record in the clustered index of SYS_INDEXES - table */ - mtr_t* mtr) /* in: mtr having the latch on the record page */ -{ - ulint root_page_no; - ulint space; - byte* ptr; - ulint len; - - ut_ad(mutex_own(&(dict_sys->mutex))); - ut_a(!dict_table_is_comp(dict_sys->sys_indexes)); - ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len); - - ut_ad(len == 4); - - root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr); - - if (root_page_no == FIL_NULL) { - /* The tree has already been freed */ - - return; - } - - ptr = rec_get_nth_field_old(rec, - DICT_SYS_INDEXES_SPACE_NO_FIELD, &len); - - ut_ad(len == 4); - - space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr); - - if (!fil_tablespace_exists_in_mem(space)) { - /* It is a single table tablespace and the .ibd file is - missing: do nothing */ - - return; - } - - /* We free all the pages but the root page first; this operation - may span several mini-transactions */ - - btr_free_but_not_root(space, root_page_no); - - /* Then we free the root page in the same mini-transaction where - we write FIL_NULL to the appropriate field in the SYS_INDEXES - record: this mini-transaction marks the B-tree totally freed */ - - /* printf("Dropping index tree in space %lu root page %lu\n", space, - root_page_no); */ - btr_free_root(space, root_page_no, mtr); - - page_rec_write_index_page_no(rec, - DICT_SYS_INDEXES_PAGE_NO_FIELD, - FIL_NULL, mtr); -} - -/*********************************************************************** -Truncates the index tree associated with a row in SYS_INDEXES table. */ - -ulint -dict_truncate_index_tree( -/*=====================*/ - /* out: new root page number, or - FIL_NULL on failure */ - dict_table_t* table, /* in: the table the index belongs to */ - btr_pcur_t* pcur, /* in/out: persistent cursor pointing to - record in the clustered index of - SYS_INDEXES table. The cursor may be - repositioned in this call. */ - mtr_t* mtr) /* in: mtr having the latch - on the record page. The mtr may be - committed and restarted in this call. */ -{ - ulint root_page_no; - ulint space; - ulint type; - dulint index_id; - rec_t* rec; - byte* ptr; - ulint len; - ulint comp; - dict_index_t* index; - - ut_ad(mutex_own(&(dict_sys->mutex))); - ut_a(!dict_table_is_comp(dict_sys->sys_indexes)); - rec = btr_pcur_get_rec(pcur); - ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len); - - ut_ad(len == 4); - - root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr); - - if (root_page_no == FIL_NULL) { - /* The tree has been freed. */ - - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Trying to TRUNCATE" - " a missing index of table %s!\n", table->name); - return(FIL_NULL); - } - - ptr = rec_get_nth_field_old(rec, - DICT_SYS_INDEXES_SPACE_NO_FIELD, &len); - - ut_ad(len == 4); - - space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr); - - if (!fil_tablespace_exists_in_mem(space)) { - /* It is a single table tablespace and the .ibd file is - missing: do nothing */ - - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Trying to TRUNCATE" - " a missing .ibd file of table %s!\n", table->name); - return(FIL_NULL); - } - - ptr = rec_get_nth_field_old(rec, - DICT_SYS_INDEXES_TYPE_FIELD, &len); - ut_ad(len == 4); - type = mach_read_from_4(ptr); - - ptr = rec_get_nth_field_old(rec, 1, &len); - ut_ad(len == 8); - index_id = mach_read_from_8(ptr); - - /* We free all the pages but the root page first; this operation - may span several mini-transactions */ - - btr_free_but_not_root(space, root_page_no); - - /* Then we free the root page in the same mini-transaction where - we create the b-tree and write its new root page number to the - appropriate field in the SYS_INDEXES record: this mini-transaction - marks the B-tree totally truncated */ - - comp = page_is_comp(btr_page_get(space, root_page_no, RW_X_LATCH, - mtr)); - - btr_free_root(space, root_page_no, mtr); - /* We will temporarily write FIL_NULL to the PAGE_NO field - in SYS_INDEXES, so that the database will not get into an - inconsistent state in case it crashes between the mtr_commit() - below and the following mtr_commit() call. */ - page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, - FIL_NULL, mtr); - - /* We will need to commit the mini-transaction in order to avoid - deadlocks in the btr_create() call, because otherwise we would - be freeing and allocating pages in the same mini-transaction. */ - btr_pcur_store_position(pcur, mtr); - mtr_commit(mtr); - - mtr_start(mtr); - btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr); - - /* Find the index corresponding to this SYS_INDEXES record. */ - for (index = UT_LIST_GET_FIRST(table->indexes); - index; - index = UT_LIST_GET_NEXT(indexes, index)) { - if (!ut_dulint_cmp(index->id, index_id)) { - break; - } - } - - root_page_no = btr_create(type, space, index_id, comp, mtr); - if (index) { - index->page = (unsigned int) root_page_no; - } else { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Index %lu %lu of table %s is missing\n" - "InnoDB: from the data dictionary during TRUNCATE!\n", - ut_dulint_get_high(index_id), - ut_dulint_get_low(index_id), - table->name); - } - - return(root_page_no); -} - -/************************************************************************* -Creates a table create graph. */ - -tab_node_t* -tab_create_graph_create( -/*====================*/ - /* out, own: table create node */ - dict_table_t* table, /* in: table to create, built as a memory data - structure */ - mem_heap_t* heap) /* in: heap where created */ -{ - tab_node_t* node; - - node = mem_heap_alloc(heap, sizeof(tab_node_t)); - - node->common.type = QUE_NODE_CREATE_TABLE; - - node->table = table; - - node->state = TABLE_BUILD_TABLE_DEF; - node->heap = mem_heap_create(256); - - node->tab_def = ins_node_create(INS_DIRECT, dict_sys->sys_tables, - heap); - node->tab_def->common.parent = node; - - node->col_def = ins_node_create(INS_DIRECT, dict_sys->sys_columns, - heap); - node->col_def->common.parent = node; - - node->commit_node = commit_node_create(heap); - node->commit_node->common.parent = node; - - return(node); -} - -/************************************************************************* -Creates an index create graph. */ - -ind_node_t* -ind_create_graph_create( -/*====================*/ - /* out, own: index create node */ - dict_index_t* index, /* in: index to create, built as a memory data - structure */ - mem_heap_t* heap) /* in: heap where created */ -{ - ind_node_t* node; - - node = mem_heap_alloc(heap, sizeof(ind_node_t)); - - node->common.type = QUE_NODE_CREATE_INDEX; - - node->index = index; - - node->state = INDEX_BUILD_INDEX_DEF; - node->page_no = FIL_NULL; - node->heap = mem_heap_create(256); - - node->ind_def = ins_node_create(INS_DIRECT, - dict_sys->sys_indexes, heap); - node->ind_def->common.parent = node; - - node->field_def = ins_node_create(INS_DIRECT, - dict_sys->sys_fields, heap); - node->field_def->common.parent = node; - - node->commit_node = commit_node_create(heap); - node->commit_node->common.parent = node; - - return(node); -} - -/*************************************************************** -Creates a table. This is a high-level function used in SQL execution graphs. */ - -que_thr_t* -dict_create_table_step( -/*===================*/ - /* out: query thread to run next or NULL */ - que_thr_t* thr) /* in: query thread */ -{ - tab_node_t* node; - ulint err = DB_ERROR; - trx_t* trx; - - ut_ad(thr); - ut_ad(mutex_own(&(dict_sys->mutex))); - - trx = thr_get_trx(thr); - - node = thr->run_node; - - ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_TABLE); - - if (thr->prev_node == que_node_get_parent(node)) { - node->state = TABLE_BUILD_TABLE_DEF; - } - - if (node->state == TABLE_BUILD_TABLE_DEF) { - - /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */ - - err = dict_build_table_def_step(thr, node); - - if (err != DB_SUCCESS) { - - goto function_exit; - } - - node->state = TABLE_BUILD_COL_DEF; - node->col_no = 0; - - thr->run_node = node->tab_def; - - return(thr); - } - - if (node->state == TABLE_BUILD_COL_DEF) { - - if (node->col_no < (node->table)->n_def) { - - err = dict_build_col_def_step(node); - - if (err != DB_SUCCESS) { - - goto function_exit; - } - - node->col_no++; - - thr->run_node = node->col_def; - - return(thr); - } else { - node->state = TABLE_COMMIT_WORK; - } - } - - if (node->state == TABLE_COMMIT_WORK) { - - /* Table was correctly defined: do NOT commit the transaction - (CREATE TABLE does NOT do an implicit commit of the current - transaction) */ - - node->state = TABLE_ADD_TO_CACHE; - - /* thr->run_node = node->commit_node; - - return(thr); */ - } - - if (node->state == TABLE_ADD_TO_CACHE) { - - dict_table_add_to_cache(node->table, node->heap); - - err = DB_SUCCESS; - } - -function_exit: - trx->error_state = err; - - if (err == DB_SUCCESS) { - /* Ok: do nothing */ - - } else if (err == DB_LOCK_WAIT) { - - return(NULL); - } else { - /* SQL error detected */ - - return(NULL); - } - - thr->run_node = que_node_get_parent(node); - - return(thr); -} - -/*************************************************************** -Creates an index. This is a high-level function used in SQL execution -graphs. */ - -que_thr_t* -dict_create_index_step( -/*===================*/ - /* out: query thread to run next or NULL */ - que_thr_t* thr) /* in: query thread */ -{ - ind_node_t* node; - ulint err = DB_ERROR; - trx_t* trx; - - ut_ad(thr); - ut_ad(mutex_own(&(dict_sys->mutex))); - - trx = thr_get_trx(thr); - - node = thr->run_node; - - ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_INDEX); - - if (thr->prev_node == que_node_get_parent(node)) { - node->state = INDEX_BUILD_INDEX_DEF; - } - - if (node->state == INDEX_BUILD_INDEX_DEF) { - /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */ - err = dict_build_index_def_step(thr, node); - - if (err != DB_SUCCESS) { - - goto function_exit; - } - - node->state = INDEX_BUILD_FIELD_DEF; - node->field_no = 0; - - thr->run_node = node->ind_def; - - return(thr); - } - - if (node->state == INDEX_BUILD_FIELD_DEF) { - - if (node->field_no < (node->index)->n_fields) { - - err = dict_build_field_def_step(node); - - if (err != DB_SUCCESS) { - - goto function_exit; - } - - node->field_no++; - - thr->run_node = node->field_def; - - return(thr); - } else { - node->state = INDEX_CREATE_INDEX_TREE; - } - } - - if (node->state == INDEX_CREATE_INDEX_TREE) { - - err = dict_create_index_tree_step(node); - - if (err != DB_SUCCESS) { - - goto function_exit; - } - - node->state = INDEX_COMMIT_WORK; - } - - if (node->state == INDEX_COMMIT_WORK) { - - /* Index was correctly defined: do NOT commit the transaction - (CREATE INDEX does NOT currently do an implicit commit of - the current transaction) */ - - node->state = INDEX_ADD_TO_CACHE; - - /* thr->run_node = node->commit_node; - - return(thr); */ - } - - if (node->state == INDEX_ADD_TO_CACHE) { - - dict_index_add_to_cache(node->table, node->index, - node->page_no); - - err = DB_SUCCESS; - } - -function_exit: - trx->error_state = err; - - if (err == DB_SUCCESS) { - /* Ok: do nothing */ - - } else if (err == DB_LOCK_WAIT) { - - return(NULL); - } else { - /* SQL error detected */ - - return(NULL); - } - - thr->run_node = que_node_get_parent(node); - - return(thr); -} - -/******************************************************************** -Creates the foreign key constraints system tables inside InnoDB -at database creation or database start if they are not found or are -not of the right form. */ - -ulint -dict_create_or_check_foreign_constraint_tables(void) -/*================================================*/ - /* out: DB_SUCCESS or error code */ -{ - dict_table_t* table1; - dict_table_t* table2; - ulint error; - trx_t* trx; - - mutex_enter(&(dict_sys->mutex)); - - table1 = dict_table_get_low("SYS_FOREIGN"); - table2 = dict_table_get_low("SYS_FOREIGN_COLS"); - - if (table1 && table2 - && UT_LIST_GET_LEN(table1->indexes) == 3 - && UT_LIST_GET_LEN(table2->indexes) == 1) { - - /* Foreign constraint system tables have already been - created, and they are ok */ - - mutex_exit(&(dict_sys->mutex)); - - return(DB_SUCCESS); - } - - mutex_exit(&(dict_sys->mutex)); - - trx = trx_allocate_for_mysql(); - - trx->op_info = "creating foreign key sys tables"; - - row_mysql_lock_data_dictionary(trx); - - if (table1) { - fprintf(stderr, - "InnoDB: dropping incompletely created" - " SYS_FOREIGN table\n"); - row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); - } - - if (table2) { - fprintf(stderr, - "InnoDB: dropping incompletely created" - " SYS_FOREIGN_COLS table\n"); - row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); - } - - fprintf(stderr, - "InnoDB: Creating foreign key constraint system tables\n"); - - /* NOTE: in dict_load_foreigns we use the fact that - there are 2 secondary indexes on SYS_FOREIGN, and they - are defined just like below */ - - /* NOTE: when designing InnoDB's foreign key support in 2001, we made - an error and made the table names and the foreign key id of type - 'CHAR' (internally, really a VARCHAR). We should have made the type - VARBINARY, like in other InnoDB system tables, to get a clean - design. */ - - error = que_eval_sql(NULL, - "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n" - "BEGIN\n" - "CREATE TABLE\n" - "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR," - " REF_NAME CHAR, N_COLS INT);\n" - "CREATE UNIQUE CLUSTERED INDEX ID_IND" - " ON SYS_FOREIGN (ID);\n" - "CREATE INDEX FOR_IND" - " ON SYS_FOREIGN (FOR_NAME);\n" - "CREATE INDEX REF_IND" - " ON SYS_FOREIGN (REF_NAME);\n" - "CREATE TABLE\n" - "SYS_FOREIGN_COLS(ID CHAR, POS INT," - " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n" - "CREATE UNIQUE CLUSTERED INDEX ID_IND" - " ON SYS_FOREIGN_COLS (ID, POS);\n" - "COMMIT WORK;\n" - "END;\n" - , FALSE, trx); - - if (error != DB_SUCCESS) { - fprintf(stderr, "InnoDB: error %lu in creation\n", - (ulong) error); - - ut_a(error == DB_OUT_OF_FILE_SPACE - || error == DB_TOO_MANY_CONCURRENT_TRXS); - - fprintf(stderr, - "InnoDB: creation failed\n" - "InnoDB: tablespace is full\n" - "InnoDB: dropping incompletely created" - " SYS_FOREIGN tables\n"); - - row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); - row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); - - error = DB_MUST_GET_MORE_FILE_SPACE; - } - - trx->op_info = ""; - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - if (error == DB_SUCCESS) { - fprintf(stderr, - "InnoDB: Foreign key constraint system tables" - " created\n"); - } - - return(error); -} - -/******************************************************************** -Evaluate the given foreign key SQL statement. */ - -ulint -dict_foreign_eval_sql( -/*==================*/ - /* out: error code or DB_SUCCESS */ - pars_info_t* info, /* in: info struct, or NULL */ - const char* sql, /* in: SQL string to evaluate */ - dict_table_t* table, /* in: table */ - dict_foreign_t* foreign,/* in: foreign */ - trx_t* trx) /* in: transaction */ -{ - ulint error; - FILE* ef = dict_foreign_err_file; - - error = que_eval_sql(info, sql, FALSE, trx); - - if (error == DB_DUPLICATE_KEY) { - mutex_enter(&dict_foreign_err_mutex); - rewind(ef); - ut_print_timestamp(ef); - fputs(" Error in foreign key constraint creation for table ", - ef); - ut_print_name(ef, trx, TRUE, table->name); - fputs(".\nA foreign key constraint of name ", ef); - ut_print_name(ef, trx, FALSE, foreign->id); - fputs("\nalready exists." - " (Note that internally InnoDB adds 'databasename/'\n" - "in front of the user-defined constraint name).\n", - ef); - fputs("Note that InnoDB's FOREIGN KEY system tables store\n" - "constraint names as case-insensitive, with the\n" - "MySQL standard latin1_swedish_ci collation. If you\n" - "create tables or databases whose names differ only in\n" - "the character case, then collisions in constraint\n" - "names can occur. Workaround: name your constraints\n" - "explicitly with unique names.\n", - ef); - - mutex_exit(&dict_foreign_err_mutex); - - return(error); - } - - if (error != DB_SUCCESS) { - fprintf(stderr, - "InnoDB: Foreign key constraint creation failed:\n" - "InnoDB: internal error number %lu\n", (ulong) error); - - mutex_enter(&dict_foreign_err_mutex); - ut_print_timestamp(ef); - fputs(" Internal error in foreign key constraint creation" - " for table ", ef); - ut_print_name(ef, trx, TRUE, table->name); - fputs(".\n" - "See the MySQL .err log in the datadir" - " for more information.\n", ef); - mutex_exit(&dict_foreign_err_mutex); - - return(error); - } - - return(DB_SUCCESS); -} - -/************************************************************************ -Add a single foreign key field definition to the data dictionary tables in -the database. */ -static -ulint -dict_create_add_foreign_field_to_dictionary( -/*========================================*/ - /* out: error code or DB_SUCCESS */ - ulint field_nr, /* in: foreign field number */ - dict_table_t* table, /* in: table */ - dict_foreign_t* foreign, /* in: foreign */ - trx_t* trx) /* in: transaction */ -{ - pars_info_t* info = pars_info_create(); - - pars_info_add_str_literal(info, "id", foreign->id); - - pars_info_add_int4_literal(info, "pos", field_nr); - - pars_info_add_str_literal(info, "for_col_name", - foreign->foreign_col_names[field_nr]); - - pars_info_add_str_literal(info, "ref_col_name", - foreign->referenced_col_names[field_nr]); - - return(dict_foreign_eval_sql( - info, - "PROCEDURE P () IS\n" - "BEGIN\n" - "INSERT INTO SYS_FOREIGN_COLS VALUES" - "(:id, :pos, :for_col_name, :ref_col_name);\n" - "END;\n", - table, foreign, trx)); -} - -/************************************************************************ -Add a single foreign key definition to the data dictionary tables in the -database. We also generate names to constraints that were not named by the -user. A generated constraint has a name of the format -databasename/tablename_ibfk_<number>, where the numbers start from 1, and -are given locally for this table, that is, the number is not global, as in -the old format constraints < 4.0.18 it used to be. */ -static -ulint -dict_create_add_foreign_to_dictionary( -/*==================================*/ - /* out: error code or DB_SUCCESS */ - ulint* id_nr, /* in/out: number to use in id generation; - incremented if used */ - dict_table_t* table, /* in: table */ - dict_foreign_t* foreign,/* in: foreign */ - trx_t* trx) /* in: transaction */ -{ - ulint error; - ulint i; - - pars_info_t* info = pars_info_create(); - - if (foreign->id == NULL) { - /* Generate a new constraint id */ - ulint namelen = strlen(table->name); - char* id = mem_heap_alloc(foreign->heap, namelen + 20); - /* no overflow if number < 1e13 */ - sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++); - foreign->id = id; - } - - pars_info_add_str_literal(info, "id", foreign->id); - - pars_info_add_str_literal(info, "for_name", table->name); - - pars_info_add_str_literal(info, "ref_name", - foreign->referenced_table_name); - - pars_info_add_int4_literal(info, "n_cols", - foreign->n_fields + (foreign->type << 24)); - - error = dict_foreign_eval_sql(info, - "PROCEDURE P () IS\n" - "BEGIN\n" - "INSERT INTO SYS_FOREIGN VALUES" - "(:id, :for_name, :ref_name, :n_cols);\n" - "END;\n" - , table, foreign, trx); - - if (error != DB_SUCCESS) { - - return(error); - } - - for (i = 0; i < foreign->n_fields; i++) { - error = dict_create_add_foreign_field_to_dictionary( - i, table, foreign, trx); - - if (error != DB_SUCCESS) { - - return(error); - } - } - - error = dict_foreign_eval_sql(NULL, - "PROCEDURE P () IS\n" - "BEGIN\n" - "COMMIT WORK;\n" - "END;\n" - , table, foreign, trx); - - return(error); -} - -/************************************************************************ -Adds foreign key definitions to data dictionary tables in the database. */ - -ulint -dict_create_add_foreigns_to_dictionary( -/*===================================*/ - /* out: error code or DB_SUCCESS */ - ulint start_id,/* in: if we are actually doing ALTER TABLE - ADD CONSTRAINT, we want to generate constraint - numbers which are bigger than in the table so - far; we number the constraints from - start_id + 1 up; start_id should be set to 0 if - we are creating a new table, or if the table - so far has no constraints for which the name - was generated here */ - dict_table_t* table, /* in: table */ - trx_t* trx) /* in: transaction */ -{ - dict_foreign_t* foreign; - ulint number = start_id + 1; - ulint error; - - ut_ad(mutex_own(&(dict_sys->mutex))); - - if (NULL == dict_table_get_low("SYS_FOREIGN")) { - fprintf(stderr, - "InnoDB: table SYS_FOREIGN not found" - " in internal data dictionary\n"); - - return(DB_ERROR); - } - - for (foreign = UT_LIST_GET_FIRST(table->foreign_list); - foreign; - foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { - - error = dict_create_add_foreign_to_dictionary(&number, table, - foreign, trx); - - if (error != DB_SUCCESS) { - - return(error); - } - } - - return(DB_SUCCESS); -} |