diff options
Diffstat (limited to 'innobase/dict')
-rw-r--r-- | innobase/dict/Makefile.am | 25 | ||||
-rw-r--r-- | innobase/dict/dict0boot.c | 423 | ||||
-rw-r--r-- | innobase/dict/dict0crea.c | 1468 | ||||
-rw-r--r-- | innobase/dict/dict0dict.c | 4474 | ||||
-rw-r--r-- | innobase/dict/dict0load.c | 1355 | ||||
-rw-r--r-- | innobase/dict/dict0mem.c | 293 | ||||
-rw-r--r-- | innobase/dict/makefilewin | 21 |
7 files changed, 0 insertions, 8059 deletions
diff --git a/innobase/dict/Makefile.am b/innobase/dict/Makefile.am deleted file mode 100644 index 0034d2f8f1e..00000000000 --- a/innobase/dict/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB -# & Innobase Oy -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -include ../include/Makefile.i - -noinst_LIBRARIES = libdict.a - -libdict_a_SOURCES = dict0boot.c dict0crea.c dict0dict.c dict0load.c\ - dict0mem.c - -EXTRA_PROGRAMS = diff --git a/innobase/dict/dict0boot.c b/innobase/dict/dict0boot.c deleted file mode 100644 index 0f6d55c9341..00000000000 --- a/innobase/dict/dict0boot.c +++ /dev/null @@ -1,423 +0,0 @@ -/****************************************************** -Data dictionary creation and booting - -(c) 1996 Innobase Oy - -Created 4/18/1996 Heikki Tuuri -*******************************************************/ - -#include "dict0boot.h" - -#ifdef UNIV_NONINL -#include "dict0boot.ic" -#endif - -#include "dict0crea.h" -#include "btr0btr.h" -#include "dict0load.h" -#include "dict0load.h" -#include "trx0trx.h" -#include "srv0srv.h" -#include "ibuf0ibuf.h" -#include "buf0flu.h" -#include "log0recv.h" -#include "os0file.h" - -/************************************************************************** -Gets a pointer to the dictionary header and x-latches its page. */ - -dict_hdr_t* -dict_hdr_get( -/*=========*/ - /* out: pointer to the dictionary header, - page x-latched */ - mtr_t* mtr) /* in: mtr */ -{ - dict_hdr_t* header; - - ut_ad(mtr); - - header = DICT_HDR + buf_page_get(DICT_HDR_SPACE, DICT_HDR_PAGE_NO, - RW_X_LATCH, mtr); -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(header, SYNC_DICT_HEADER); -#endif /* UNIV_SYNC_DEBUG */ - return(header); -} - -/************************************************************************** -Returns a new table, index, or tree id. */ - -dulint -dict_hdr_get_new_id( -/*================*/ - /* out: the new id */ - ulint type) /* in: DICT_HDR_ROW_ID, ... */ -{ - dict_hdr_t* dict_hdr; - dulint id; - mtr_t mtr; - - ut_ad((type == DICT_HDR_TABLE_ID) || (type == DICT_HDR_INDEX_ID) - || (type == DICT_HDR_MIX_ID)); - - mtr_start(&mtr); - - dict_hdr = dict_hdr_get(&mtr); - - id = mtr_read_dulint(dict_hdr + type, &mtr); - - /* Add some dummy code here because otherwise pgcc seems to - compile wrong */ - - if (0 == ut_dulint_cmp(id, ut_dulint_max)) { - /* TO DO: remove this code, or make it conditional */ - ut_dbg_null_ptr = 0; - } - - id = ut_dulint_add(id, 1); - - mlog_write_dulint(dict_hdr + type, id, &mtr); - - mtr_commit(&mtr); - - return(id); -} - -/************************************************************************** -Writes the current value of the row id counter to the dictionary header file -page. */ - -void -dict_hdr_flush_row_id(void) -/*=======================*/ -{ - dict_hdr_t* dict_hdr; - dulint id; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - id = dict_sys->row_id; - - mtr_start(&mtr); - - dict_hdr = dict_hdr_get(&mtr); - - mlog_write_dulint(dict_hdr + DICT_HDR_ROW_ID, id, &mtr); - - mtr_commit(&mtr); -} - -/********************************************************************* -Creates the file page for the dictionary header. This function is -called only at the database creation. */ -static -ibool -dict_hdr_create( -/*============*/ - /* out: TRUE if succeed */ - mtr_t* mtr) /* in: mtr */ -{ - dict_hdr_t* dict_header; - ulint hdr_page_no; - ulint root_page_no; - page_t* page; - - ut_ad(mtr); - - /* Create the dictionary header file block in a new, allocated file - segment in the system tablespace */ - page = fseg_create(DICT_HDR_SPACE, 0, - DICT_HDR + DICT_HDR_FSEG_HEADER, mtr); - - hdr_page_no = buf_frame_get_page_no(page); - - ut_a(DICT_HDR_PAGE_NO == hdr_page_no); - - dict_header = dict_hdr_get(mtr); - - /* Start counting row, table, index, and tree ids from - DICT_HDR_FIRST_ID */ - mlog_write_dulint(dict_header + DICT_HDR_ROW_ID, - ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); - - mlog_write_dulint(dict_header + DICT_HDR_TABLE_ID, - ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); - - mlog_write_dulint(dict_header + DICT_HDR_INDEX_ID, - ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); - - mlog_write_dulint(dict_header + DICT_HDR_MIX_ID, - ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); - - /* Create the B-tree roots for the clustered indexes of the basic - system tables */ - - /*--------------------------*/ - root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, - DICT_HDR_SPACE, DICT_TABLES_ID, FALSE, mtr); - if (root_page_no == FIL_NULL) { - - return(FALSE); - } - - mlog_write_ulint(dict_header + DICT_HDR_TABLES, root_page_no, - MLOG_4BYTES, mtr); - /*--------------------------*/ - root_page_no = btr_create(DICT_UNIQUE, DICT_HDR_SPACE, - DICT_TABLE_IDS_ID, FALSE, mtr); - if (root_page_no == FIL_NULL) { - - return(FALSE); - } - - mlog_write_ulint(dict_header + DICT_HDR_TABLE_IDS, root_page_no, - MLOG_4BYTES, mtr); - /*--------------------------*/ - root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, - DICT_HDR_SPACE, DICT_COLUMNS_ID, FALSE, mtr); - if (root_page_no == FIL_NULL) { - - return(FALSE); - } - - mlog_write_ulint(dict_header + DICT_HDR_COLUMNS, root_page_no, - MLOG_4BYTES, mtr); - /*--------------------------*/ - root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, - DICT_HDR_SPACE, DICT_INDEXES_ID, FALSE, mtr); - if (root_page_no == FIL_NULL) { - - return(FALSE); - } - - mlog_write_ulint(dict_header + DICT_HDR_INDEXES, root_page_no, - MLOG_4BYTES, mtr); - /*--------------------------*/ - root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, - DICT_HDR_SPACE, DICT_FIELDS_ID, FALSE, mtr); - if (root_page_no == FIL_NULL) { - - return(FALSE); - } - - mlog_write_ulint(dict_header + DICT_HDR_FIELDS, root_page_no, - MLOG_4BYTES, mtr); - /*--------------------------*/ - - return(TRUE); -} - -/********************************************************************* -Initializes the data dictionary memory structures when the database is -started. This function is also called when the data dictionary is created. */ - -void -dict_boot(void) -/*===========*/ -{ - dict_table_t* table; - dict_index_t* index; - dict_hdr_t* dict_hdr; - mtr_t mtr; - ibool success; - - mtr_start(&mtr); - - /* Create the hash tables etc. */ - dict_init(); - - mutex_enter(&(dict_sys->mutex)); - - /* Get the dictionary header */ - dict_hdr = dict_hdr_get(&mtr); - - /* Because we only write new row ids to disk-based data structure - (dictionary header) when it is divisible by - DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover - the latest value of the row id counter. Therefore we advance - the counter at the database startup to avoid overlapping values. - Note that when a user after database startup first time asks for - a new row id, then because the counter is now divisible by - ..._MARGIN, it will immediately be updated to the disk-based - header. */ - - dict_sys->row_id = ut_dulint_add( - ut_dulint_align_up( - mtr_read_dulint(dict_hdr + DICT_HDR_ROW_ID, - &mtr), - DICT_HDR_ROW_ID_WRITE_MARGIN), - DICT_HDR_ROW_ID_WRITE_MARGIN); - - /* Insert into the dictionary cache the descriptions of the basic - system tables */ - /*-------------------------*/ - table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, FALSE); - - dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0, 0); - dict_mem_table_add_col(table, "ID", DATA_BINARY, 0, 0, 0); - dict_mem_table_add_col(table, "N_COLS", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "TYPE", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "MIX_ID", DATA_BINARY, 0, 0, 0); - dict_mem_table_add_col(table, "MIX_LEN", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "CLUSTER_NAME", DATA_BINARY, 0, 0, 0); - dict_mem_table_add_col(table, "SPACE", DATA_INT, 0, 4, 0); - - table->id = DICT_TABLES_ID; - - dict_table_add_to_cache(table); - dict_sys->sys_tables = table; - - index = dict_mem_index_create("SYS_TABLES", "CLUST_IND", - DICT_HDR_SPACE, DICT_UNIQUE | DICT_CLUSTERED, 1); - - dict_mem_index_add_field(index, "NAME", 0, 0); - - index->id = DICT_TABLES_ID; - - success = dict_index_add_to_cache(table, index, mtr_read_ulint( - dict_hdr + DICT_HDR_TABLES, MLOG_4BYTES, &mtr)); - ut_a(success); - /*-------------------------*/ - index = dict_mem_index_create("SYS_TABLES", "ID_IND", - DICT_HDR_SPACE, DICT_UNIQUE, 1); - dict_mem_index_add_field(index, "ID", 0, 0); - - index->id = DICT_TABLE_IDS_ID; - success = dict_index_add_to_cache(table, index, mtr_read_ulint( - dict_hdr + DICT_HDR_TABLE_IDS, MLOG_4BYTES, &mtr)); - ut_a(success); - /*-------------------------*/ - table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, FALSE); - - dict_mem_table_add_col(table, "TABLE_ID", DATA_BINARY,0,0,0); - dict_mem_table_add_col(table, "POS", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0, 0); - dict_mem_table_add_col(table, "MTYPE", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "PRTYPE", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "LEN", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "PREC", DATA_INT, 0, 4, 0); - - table->id = DICT_COLUMNS_ID; - - dict_table_add_to_cache(table); - dict_sys->sys_columns = table; - - index = dict_mem_index_create("SYS_COLUMNS", "CLUST_IND", - DICT_HDR_SPACE, DICT_UNIQUE | DICT_CLUSTERED, 2); - - dict_mem_index_add_field(index, "TABLE_ID", 0, 0); - dict_mem_index_add_field(index, "POS", 0, 0); - - index->id = DICT_COLUMNS_ID; - success = dict_index_add_to_cache(table, index, mtr_read_ulint( - dict_hdr + DICT_HDR_COLUMNS, MLOG_4BYTES, &mtr)); - ut_a(success); - /*-------------------------*/ - table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, FALSE); - - dict_mem_table_add_col(table, "TABLE_ID", DATA_BINARY, 0,0,0); - dict_mem_table_add_col(table, "ID", DATA_BINARY, 0, 0, 0); - dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0, 0); - dict_mem_table_add_col(table, "N_FIELDS", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "TYPE", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "SPACE", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "PAGE_NO", DATA_INT, 0, 4, 0); - - /* The '+ 2' below comes from the 2 system fields */ -#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2 -#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2" -#endif -#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2 -#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2" -#endif -#if DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2 -#error "DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2" -#endif - - table->id = DICT_INDEXES_ID; - dict_table_add_to_cache(table); - dict_sys->sys_indexes = table; - - index = dict_mem_index_create("SYS_INDEXES", "CLUST_IND", - DICT_HDR_SPACE, DICT_UNIQUE | DICT_CLUSTERED, 2); - - dict_mem_index_add_field(index, "TABLE_ID", 0, 0); - dict_mem_index_add_field(index, "ID", 0, 0); - - index->id = DICT_INDEXES_ID; - success = dict_index_add_to_cache(table, index, mtr_read_ulint( - dict_hdr + DICT_HDR_INDEXES, MLOG_4BYTES, &mtr)); - ut_a(success); - /*-------------------------*/ - table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, FALSE); - - dict_mem_table_add_col(table, "INDEX_ID", DATA_BINARY, 0,0,0); - dict_mem_table_add_col(table, "POS", DATA_INT, 0, 4, 0); - dict_mem_table_add_col(table, "COL_NAME", DATA_BINARY, 0,0,0); - - table->id = DICT_FIELDS_ID; - dict_table_add_to_cache(table); - dict_sys->sys_fields = table; - - index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND", - DICT_HDR_SPACE, DICT_UNIQUE | DICT_CLUSTERED, 2); - - dict_mem_index_add_field(index, "INDEX_ID", 0, 0); - dict_mem_index_add_field(index, "POS", 0, 0); - - index->id = DICT_FIELDS_ID; - success = dict_index_add_to_cache(table, index, mtr_read_ulint( - dict_hdr + DICT_HDR_FIELDS, MLOG_4BYTES, &mtr)); - ut_a(success); - - mtr_commit(&mtr); - /*-------------------------*/ - - /* Initialize the insert buffer table and index for each tablespace */ - - ibuf_init_at_db_start(); - - /* Load definitions of other indexes on system tables */ - - dict_load_sys_table(dict_sys->sys_tables); - dict_load_sys_table(dict_sys->sys_columns); - dict_load_sys_table(dict_sys->sys_indexes); - dict_load_sys_table(dict_sys->sys_fields); - - mutex_exit(&(dict_sys->mutex)); -} - -/********************************************************************* -Inserts the basic system table data into themselves in the database -creation. */ -static -void -dict_insert_initial_data(void) -/*==========================*/ -{ - /* Does nothing yet */ -} - -/********************************************************************* -Creates and initializes the data dictionary at the database creation. */ - -void -dict_create(void) -/*=============*/ -{ - mtr_t mtr; - - mtr_start(&mtr); - - dict_hdr_create(&mtr); - - mtr_commit(&mtr); - - dict_boot(); - - dict_insert_initial_data(); -} diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c deleted file mode 100644 index 1f12386e413..00000000000 --- a/innobase/dict/dict0crea.c +++ /dev/null @@ -1,1468 +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" - -/********************************************************************* -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); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, table->n_def - | ((ulint) table->comp << 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, table->type); - - dfield_set_data(dfield, ptr, 4); - /* 6: MIX_ID ---------------------------*/ - dfield = dtuple_get_nth_field(entry, 4); - - ptr = mem_heap_alloc(heap, 8); - mach_write_to_8(ptr, table->mix_id); - - dfield_set_data(dfield, ptr, 8); - /* 7: MIX_LEN --------------------------*/ - - dfield = dtuple_get_nth_field(entry, 5); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, table->mix_len); - - dfield_set_data(dfield, ptr, 4); - /* 8: CLUSTER_NAME ---------------------*/ - dfield = dtuple_get_nth_field(entry, 6); - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - dfield_set_data(dfield, table->cluster_name, - ut_strlen(table->cluster_name)); - ut_error; /* Oracle-style clusters are not supported yet */ - } else { - dfield_set_data(dfield, NULL, UNIV_SQL_NULL); - } - /* 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; - dict_col_t* column; - dfield_t* dfield; - byte* ptr; - - 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); - - dfield_set_data(dfield, column->name, ut_strlen(column->name)); - /* 5: MTYPE --------------------------*/ - dfield = dtuple_get_nth_field(entry, 3); - - ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, (column->type).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->type).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->type).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, (column->type).prec); - - 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; - dict_table_t* cluster_table; - dtuple_t* row; - ulint error; - const char* path_or_name; - ibool is_path; - mtr_t mtr; - ulint i; - ulint row_len; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - 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 += dtype_get_min_size(dict_col_get_type( - &table->cols[i])); - } - if (row_len > BTR_PAGE_MAX_REC_SIZE) { - return(DB_TOO_BIG_RECORD); - } - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - cluster_table = dict_table_get_low(table->cluster_name); - - if (cluster_table == NULL) { - - return(DB_CLUSTER_NOT_FOUND); - } - - /* Inherit space and mix len from the cluster */ - - table->space = cluster_table->space; - table->mix_len = cluster_table->mix_len; - - table->mix_id = dict_hdr_get_new_id(DICT_HDR_MIX_ID); - } - - 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. */ - - table->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( - &(table->space), path_or_name, is_path, - FIL_IBD_FILE_INITIAL_SIZE); - 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; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - 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; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - 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; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - index = node->index; - table = node->table; - - sys_indexes = dict_sys->sys_indexes; - - if (index->type & DICT_CLUSTERED - && table->type == DICT_TABLE_CLUSTER_MEMBER) { - - /* Do not create a new index tree: entries are put to the - cluster tree */ - - return(DB_SUCCESS); - } - - /* 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, - table->comp, &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; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - ut_a(!dict_sys->sys_indexes->comp); - 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 */ - 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. The mtr may be - committed and restarted in this call. */ -{ - ulint root_page_no; - ulint space; - ulint type; - dulint index_id; - byte* ptr; - ulint len; - ibool comp; - dict_index_t* index; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - ut_a(!dict_sys->sys_indexes->comp); - 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. */ - mtr_commit(mtr); - /* mtr_commit() will invalidate rec. */ - rec = NULL; - mtr_start(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->tree->page = 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); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - 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); - - 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; - ibool success; - ulint err = DB_ERROR; - trx_t* trx; - - ut_ad(thr); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - 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) { - - success = dict_index_add_to_cache(node->table, node->index, - node->page_no); - - ut_a(success); - - 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; - que_thr_t* thr; - que_t* graph; - ulint error; - trx_t* trx; - const char* str; - - 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. */ - - str = - "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"; - - graph = pars_sql(str); - - ut_a(graph); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - error = trx->error_state; - - if (error != DB_SUCCESS) { - fprintf(stderr, "InnoDB: error %lu in creation\n", - (ulong) error); - - ut_a(error == DB_OUT_OF_FILE_SPACE); - - fprintf(stderr, "InnoDB: creation failed\n"); - fprintf(stderr, "InnoDB: tablespace is full\n"); - fprintf(stderr, - "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; - } - - que_graph_free(graph); - - 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); -} - -/************************************************************************ -Adds foreign key definitions to data dictionary tables in the database. We -look at table->foreign_list, and 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. */ - -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; - que_thr_t* thr; - que_t* graph; - ulint number = start_id + 1; - ulint len; - ulint error; - FILE* ef = dict_foreign_err_file; - ulint i; - char* sql; - char* sqlend; - /* This procedure builds an InnoDB stored procedure which will insert - the necessary rows into SYS_FOREIGN and SYS_FOREIGN_COLS. */ - static const char str1[] = "PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n" - "BEGIN\n" - "INSERT INTO SYS_FOREIGN VALUES("; - static const char str2[] = ");\n"; - static const char str3[] = - "INSERT INTO SYS_FOREIGN_COLS VALUES("; - static const char str4[] = - "COMMIT WORK;\n" - "END;\n"; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - if (NULL == dict_table_get_low("SYS_FOREIGN")) { - fprintf(stderr, - "InnoDB: table SYS_FOREIGN not found from internal data dictionary\n"); - - return(DB_ERROR); - } - - foreign = UT_LIST_GET_FIRST(table->foreign_list); -loop: - if (foreign == NULL) { - - return(DB_SUCCESS); - } - - 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) number++); - foreign->id = id; - } - - len = (sizeof str1) + (sizeof str2) + (sizeof str4) - 3 - + 9/* ' and , chars */ + 10/* 32-bit integer */ - + ut_strlenq(foreign->id, '\'') * (foreign->n_fields + 1) - + ut_strlenq(table->name, '\'') - + ut_strlenq(foreign->referenced_table_name, '\''); - - for (i = 0; i < foreign->n_fields; i++) { - len += 9/* ' and , chars */ + 10/* 32-bit integer */ - + (sizeof str3) + (sizeof str2) - 2 - + ut_strlenq(foreign->foreign_col_names[i], '\'') - + ut_strlenq(foreign->referenced_col_names[i], '\''); - } - - sql = sqlend = mem_alloc(len + 1); - - /* INSERT INTO SYS_FOREIGN VALUES(...); */ - memcpy(sqlend, str1, (sizeof str1) - 1); - sqlend += (sizeof str1) - 1; - *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', foreign->id); - *sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', table->name); - *sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', foreign->referenced_table_name); - *sqlend++ = '\'', *sqlend++ = ','; - sqlend += sprintf(sqlend, "%010lu", - foreign->n_fields + (foreign->type << 24)); - memcpy(sqlend, str2, (sizeof str2) - 1); - sqlend += (sizeof str2) - 1; - - for (i = 0; i < foreign->n_fields; i++) { - /* INSERT INTO SYS_FOREIGN_COLS VALUES(...); */ - memcpy(sqlend, str3, (sizeof str3) - 1); - sqlend += (sizeof str3) - 1; - *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', foreign->id); - *sqlend++ = '\''; *sqlend++ = ','; - sqlend += sprintf(sqlend, "%010lu", (ulong) i); - *sqlend++ = ','; *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', - foreign->foreign_col_names[i]); - *sqlend++ = '\''; *sqlend++ = ','; *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', - foreign->referenced_col_names[i]); - *sqlend++ = '\''; - memcpy(sqlend, str2, (sizeof str2) - 1); - sqlend += (sizeof str2) - 1; - } - - memcpy(sqlend, str4, sizeof str4); - sqlend += sizeof str4; - - ut_a(sqlend == sql + len + 1); - - graph = pars_sql(sql); - - ut_a(graph); - - mem_free(sql); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - error = trx->error_state; - - que_graph_free(graph); - - 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, table->name); - fputs(".\nA foreign key constraint of name ", ef); - ut_print_name(ef, trx, 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, 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); - } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - - goto loop; -} diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c deleted file mode 100644 index 02f46ea7b18..00000000000 --- a/innobase/dict/dict0dict.c +++ /dev/null @@ -1,4474 +0,0 @@ -/********************************************************************** -Data dictionary system - -(c) 1996 Innobase Oy - -Created 1/8/1996 Heikki Tuuri -***********************************************************************/ - -#include "dict0dict.h" - -#ifdef UNIV_NONINL -#include "dict0dict.ic" -#endif - -#include "buf0buf.h" -#include "data0type.h" -#include "mach0data.h" -#include "dict0boot.h" -#include "dict0mem.h" -#include "dict0crea.h" -#include "trx0undo.h" -#include "btr0btr.h" -#include "btr0cur.h" -#include "btr0sea.h" -#include "pars0pars.h" -#include "pars0sym.h" -#include "que0que.h" -#include "rem0cmp.h" - -dict_sys_t* dict_sys = NULL; /* the dictionary system */ - -rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve - this in X-mode; implicit or backround - operations purge, rollback, foreign - key checks reserve this in S-mode; we - cannot trust that MySQL protects - implicit or background operations - a table drop since MySQL does not - know of them; therefore we need this; - NOTE: a transaction which reserves - this must keep book on the mode in - trx->dict_operation_lock_mode */ - -#define DICT_HEAP_SIZE 100 /* initial memory heap size when - creating a table or index object */ -#define DICT_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table - hash table fixed size in bytes */ -#define DICT_POOL_PER_COL_HASH 128 /* buffer pool max size per column - hash table fixed size in bytes */ -#define DICT_POOL_PER_VARYING 4 /* buffer pool max size per data - dictionary varying size in bytes */ - -/* Identifies generated InnoDB foreign key names */ -static char dict_ibfk[] = "_ibfk_"; - -#ifndef UNIV_HOTBACKUP -/********************************************************************** -Compares NUL-terminated UTF-8 strings case insensitively. - -NOTE: the prototype of this function is copied from ha_innodb.cc! If you change -this function, you MUST change also the prototype here! */ -extern -int -innobase_strcasecmp( -/*================*/ - /* out: 0 if a=b, <0 if a<b, >1 if a>b */ - const char* a, /* in: first string to compare */ - const char* b); /* in: second string to compare */ - -/********************************************************************** -Makes all characters in a NUL-terminated UTF-8 string lower case. - -NOTE: the prototype of this function is copied from ha_innodb.cc! If you change -this function, you MUST change also the prototype here! */ -extern -void -innobase_casedn_str( -/*================*/ - char* a); /* in/out: string to put in lower case */ -#endif /* !UNIV_HOTBACKUP */ - -/************************************************************************** -Adds a column to the data dictionary hash table. */ -static -void -dict_col_add_to_cache( -/*==================*/ - dict_table_t* table, /* in: table */ - dict_col_t* col); /* in: column */ -/************************************************************************** -Repositions a column in the data dictionary hash table when the table name -changes. */ -static -void -dict_col_reposition_in_cache( -/*=========================*/ - dict_table_t* table, /* in: table */ - dict_col_t* col, /* in: column */ - const char* new_name); /* in: new table name */ -/************************************************************************** -Removes a column from the data dictionary hash table. */ -static -void -dict_col_remove_from_cache( -/*=======================*/ - dict_table_t* table, /* in: table */ - dict_col_t* col); /* in: column */ -/************************************************************************** -Removes an index from the dictionary cache. */ -static -void -dict_index_remove_from_cache( -/*=========================*/ - dict_table_t* table, /* in: table */ - dict_index_t* index); /* in, own: index */ -/*********************************************************************** -Copies fields contained in index2 to index1. */ -static -void -dict_index_copy( -/*============*/ - dict_index_t* index1, /* in: index to copy to */ - dict_index_t* index2, /* in: index to copy from */ - ulint start, /* in: first position to copy */ - ulint end); /* in: last position to copy */ -/*********************************************************************** -Tries to find column names for the index in the column hash table and -sets the col field of the index. */ -static -ibool -dict_index_find_cols( -/*=================*/ - /* out: TRUE if success */ - dict_table_t* table, /* in: table */ - dict_index_t* index); /* in: index */ -/*********************************************************************** -Builds the internal dictionary cache representation for a clustered -index, containing also system fields not defined by the user. */ -static -dict_index_t* -dict_index_build_internal_clust( -/*============================*/ - /* out, own: the internal representation - of the clustered index */ - dict_table_t* table, /* in: table */ - dict_index_t* index); /* in: user representation of a clustered - index */ -/*********************************************************************** -Builds the internal dictionary cache representation for a non-clustered -index, containing also system fields not defined by the user. */ -static -dict_index_t* -dict_index_build_internal_non_clust( -/*================================*/ - /* out, own: the internal representation - of the non-clustered index */ - dict_table_t* table, /* in: table */ - dict_index_t* index); /* in: user representation of a non-clustered - index */ -/************************************************************************** -Removes a foreign constraint struct from the dictionary cache. */ -static -void -dict_foreign_remove_from_cache( -/*===========================*/ - dict_foreign_t* foreign); /* in, own: foreign constraint */ -/************************************************************************** -Prints a column data. */ -static -void -dict_col_print_low( -/*===============*/ - dict_col_t* col); /* in: column */ -/************************************************************************** -Prints an index data. */ -static -void -dict_index_print_low( -/*=================*/ - dict_index_t* index); /* in: index */ -/************************************************************************** -Prints a field data. */ -static -void -dict_field_print_low( -/*=================*/ - dict_field_t* field); /* in: field */ -/************************************************************************* -Frees a foreign key struct. */ -static -void -dict_foreign_free( -/*==============*/ - dict_foreign_t* foreign); /* in, own: foreign key struct */ - -/* Stream for storing detailed information about the latest foreign key -and unique key errors */ -FILE* dict_foreign_err_file = NULL; -mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign - and unique error buffers */ - - -/************************************************************************ -Checks if the database name in two table names is the same. */ - -ibool -dict_tables_have_same_db( -/*=====================*/ - /* out: TRUE if same db name */ - const char* name1, /* in: table name in the form - dbname '/' tablename */ - const char* name2) /* in: table name in the form - dbname '/' tablename */ -{ - for (; *name1 == *name2; name1++, name2++) { - if (*name1 == '/') { - return(TRUE); - } - ut_a(*name1); /* the names must contain '/' */ - } - return(FALSE); -} - -/************************************************************************ -Return the end of table name where we have removed dbname and '/'. */ -static -const char* -dict_remove_db_name( -/*================*/ - /* out: table name */ - const char* name) /* in: table name in the form - dbname '/' tablename */ -{ - const char* s; - s = strchr(name, '/'); - ut_a(s); - if (s) s++; - return(s); -} - -/************************************************************************ -Get the database name length in a table name. */ - -ulint -dict_get_db_name_len( -/*=================*/ - /* out: database name length */ - const char* name) /* in: table name in the form - dbname '/' tablename */ -{ - const char* s; - s = strchr(name, '/'); - ut_a(s); - return(s - name); -} - -/************************************************************************ -Reserves the dictionary system mutex for MySQL. */ - -void -dict_mutex_enter_for_mysql(void) -/*============================*/ -{ - mutex_enter(&(dict_sys->mutex)); -} - -/************************************************************************ -Releases the dictionary system mutex for MySQL. */ - -void -dict_mutex_exit_for_mysql(void) -/*===========================*/ -{ - mutex_exit(&(dict_sys->mutex)); -} - -/************************************************************************ -Decrements the count of open MySQL handles to a table. */ - -void -dict_table_decrement_handle_count( -/*==============================*/ - dict_table_t* table) /* in: table */ -{ - mutex_enter(&(dict_sys->mutex)); - - ut_a(table->n_mysql_handles_opened > 0); - - table->n_mysql_handles_opened--; - - mutex_exit(&(dict_sys->mutex)); -} - -/************************************************************************ -Gets the nth column of a table. */ - -dict_col_t* -dict_table_get_nth_col_noninline( -/*=============================*/ - /* out: pointer to column object */ - dict_table_t* table, /* in: table */ - ulint pos) /* in: position of column */ -{ - return(dict_table_get_nth_col(table, pos)); -} - -/************************************************************************ -Gets the first index on the table (the clustered index). */ - -dict_index_t* -dict_table_get_first_index_noninline( -/*=================================*/ - /* out: index, NULL if none exists */ - dict_table_t* table) /* in: table */ -{ - return(dict_table_get_first_index(table)); -} - -/************************************************************************ -Gets the next index on the table. */ - -dict_index_t* -dict_table_get_next_index_noninline( -/*================================*/ - /* out: index, NULL if none left */ - dict_index_t* index) /* in: index */ -{ - return(dict_table_get_next_index(index)); -} - -/************************************************************************** -Returns an index object. */ - -dict_index_t* -dict_table_get_index_noninline( -/*===========================*/ - /* out: index, NULL if does not exist */ - dict_table_t* table, /* in: table */ - const char* name) /* in: index name */ -{ - return(dict_table_get_index(table, name)); -} - -/************************************************************************ -Initializes the autoinc counter. It is not an error to initialize an already -initialized counter. */ - -void -dict_table_autoinc_initialize( -/*==========================*/ - dict_table_t* table, /* in: table */ - ib_longlong value) /* in: next value to assign to a row */ -{ - mutex_enter(&(table->autoinc_mutex)); - - table->autoinc_inited = TRUE; - table->autoinc = value; - - mutex_exit(&(table->autoinc_mutex)); -} - -/************************************************************************ -Gets the next autoinc value (== autoinc counter value), 0 if not yet -initialized. If initialized, increments the counter by 1. */ - -ib_longlong -dict_table_autoinc_get( -/*===================*/ - /* out: value for a new row, or 0 */ - dict_table_t* table) /* in: table */ -{ - ib_longlong value; - - mutex_enter(&(table->autoinc_mutex)); - - if (!table->autoinc_inited) { - - value = 0; - } else { - value = table->autoinc; - table->autoinc = table->autoinc + 1; - } - - mutex_exit(&(table->autoinc_mutex)); - - return(value); -} - -/************************************************************************ -Decrements the autoinc counter value by 1. */ - -void -dict_table_autoinc_decrement( -/*=========================*/ - dict_table_t* table) /* in: table */ -{ - mutex_enter(&(table->autoinc_mutex)); - - table->autoinc = table->autoinc - 1; - - mutex_exit(&(table->autoinc_mutex)); -} - -/************************************************************************ -Reads the next autoinc value (== autoinc counter value), 0 if not yet -initialized. */ - -ib_longlong -dict_table_autoinc_read( -/*====================*/ - /* out: value for a new row, or 0 */ - dict_table_t* table) /* in: table */ -{ - ib_longlong value; - - mutex_enter(&(table->autoinc_mutex)); - - if (!table->autoinc_inited) { - - value = 0; - } else { - value = table->autoinc; - } - - mutex_exit(&(table->autoinc_mutex)); - - return(value); -} - -/************************************************************************ -Peeks the autoinc counter value, 0 if not yet initialized. Does not -increment the counter. The read not protected by any mutex! */ - -ib_longlong -dict_table_autoinc_peek( -/*====================*/ - /* out: value of the counter */ - dict_table_t* table) /* in: table */ -{ - ib_longlong value; - - if (!table->autoinc_inited) { - - value = 0; - } else { - value = table->autoinc; - } - - return(value); -} - -/************************************************************************ -Updates the autoinc counter if the value supplied is equal or bigger than the -current value. If not inited, does nothing. */ - -void -dict_table_autoinc_update( -/*======================*/ - - dict_table_t* table, /* in: table */ - ib_longlong value) /* in: value which was assigned to a row */ -{ - mutex_enter(&(table->autoinc_mutex)); - - if (table->autoinc_inited) { - if (value >= table->autoinc) { - table->autoinc = value + 1; - } - } - - mutex_exit(&(table->autoinc_mutex)); -} - -/************************************************************************ -Looks for column n in an index. */ - -ulint -dict_index_get_nth_col_pos( -/*=======================*/ - /* out: position in internal representation - of the index; if not contained, returns - ULINT_UNDEFINED */ - dict_index_t* index, /* in: index */ - ulint n) /* in: column number */ -{ - dict_field_t* field; - dict_col_t* col; - ulint pos; - ulint n_fields; - - ut_ad(index); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - - col = dict_table_get_nth_col(index->table, n); - - if (index->type & DICT_CLUSTERED) { - - return(col->clust_pos); - } - - n_fields = dict_index_get_n_fields(index); - - for (pos = 0; pos < n_fields; pos++) { - field = dict_index_get_nth_field(index, pos); - - if (col == field->col && field->prefix_len == 0) { - - return(pos); - } - } - - return(ULINT_UNDEFINED); -} - -/************************************************************************ -Returns TRUE if the index contains a column or a prefix of that column. */ - -ibool -dict_index_contains_col_or_prefix( -/*==============================*/ - /* out: TRUE if contains the column or its - prefix */ - dict_index_t* index, /* in: index */ - ulint n) /* in: column number */ -{ - dict_field_t* field; - dict_col_t* col; - ulint pos; - ulint n_fields; - - ut_ad(index); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - - if (index->type & DICT_CLUSTERED) { - - return(TRUE); - } - - col = dict_table_get_nth_col(index->table, n); - - n_fields = dict_index_get_n_fields(index); - - for (pos = 0; pos < n_fields; pos++) { - field = dict_index_get_nth_field(index, pos); - - if (col == field->col) { - - return(TRUE); - } - } - - return(FALSE); -} - -/************************************************************************ -Looks for a matching field in an index. The column has to be the same. The -column in index must be complete, or must contain a prefix longer than the -column in index2. That is, we must be able to construct the prefix in index2 -from the prefix in index. */ - -ulint -dict_index_get_nth_field_pos( -/*=========================*/ - /* out: position in internal representation - of the index; if not contained, returns - ULINT_UNDEFINED */ - dict_index_t* index, /* in: index from which to search */ - dict_index_t* index2, /* in: index */ - ulint n) /* in: field number in index2 */ -{ - dict_field_t* field; - dict_field_t* field2; - ulint n_fields; - ulint pos; - - ut_ad(index); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - - field2 = dict_index_get_nth_field(index2, n); - - n_fields = dict_index_get_n_fields(index); - - for (pos = 0; pos < n_fields; pos++) { - field = dict_index_get_nth_field(index, pos); - - if (field->col == field2->col - && (field->prefix_len == 0 - || (field->prefix_len >= field2->prefix_len - && field2->prefix_len != 0))) { - - return(pos); - } - } - - return(ULINT_UNDEFINED); -} - -/************************************************************************** -Returns a table object, based on table id, and memoryfixes it. */ - -dict_table_t* -dict_table_get_on_id( -/*=================*/ - /* out: table, NULL if does not exist */ - dulint table_id, /* in: table id */ - trx_t* trx) /* in: transaction handle */ -{ - dict_table_t* table; - - if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0 - || trx->dict_operation_lock_mode == RW_X_LATCH) { - /* It is a system table which will always exist in the table - cache: we avoid acquiring the dictionary mutex, because - if we are doing a rollback to handle an error in TABLE - CREATE, for example, we already have the mutex! */ - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - return(dict_table_get_on_id_low(table_id, trx)); - } - - mutex_enter(&(dict_sys->mutex)); - - table = dict_table_get_on_id_low(table_id, trx); - - mutex_exit(&(dict_sys->mutex)); - - return(table); -} - -/************************************************************************ -Looks for column n position in the clustered index. */ - -ulint -dict_table_get_nth_col_pos( -/*=======================*/ - /* out: position in internal representation - of the clustered index */ - dict_table_t* table, /* in: table */ - ulint n) /* in: column number */ -{ - return(dict_index_get_nth_col_pos(dict_table_get_first_index(table), - n)); -} - -/************************************************************************ -Checks if a column is in the ordering columns of the clustered index of a -table. Column prefixes are treated like whole columns. */ - -ibool -dict_table_col_in_clustered_key( -/*============================*/ - /* out: TRUE if the column, or its prefix, is - in the clustered key */ - dict_table_t* table, /* in: table */ - ulint n) /* in: column number */ -{ - dict_index_t* index; - dict_field_t* field; - dict_col_t* col; - ulint pos; - ulint n_fields; - - ut_ad(table); - - col = dict_table_get_nth_col(table, n); - - index = dict_table_get_first_index(table); - - n_fields = dict_index_get_n_unique(index); - - for (pos = 0; pos < n_fields; pos++) { - field = dict_index_get_nth_field(index, pos); - - if (col == field->col) { - - return(TRUE); - } - } - - return(FALSE); -} - -/************************************************************************** -Inits the data dictionary module. */ - -void -dict_init(void) -/*===========*/ -{ - dict_sys = mem_alloc(sizeof(dict_sys_t)); - - mutex_create(&(dict_sys->mutex)); - mutex_set_level(&(dict_sys->mutex), SYNC_DICT); - - dict_sys->table_hash = hash_create(buf_pool_get_max_size() / - (DICT_POOL_PER_TABLE_HASH * - UNIV_WORD_SIZE)); - dict_sys->table_id_hash = hash_create(buf_pool_get_max_size() / - (DICT_POOL_PER_TABLE_HASH * - UNIV_WORD_SIZE)); - dict_sys->col_hash = hash_create(buf_pool_get_max_size() / - (DICT_POOL_PER_COL_HASH * - UNIV_WORD_SIZE)); - dict_sys->size = 0; - - UT_LIST_INIT(dict_sys->table_LRU); - - rw_lock_create(&dict_operation_lock); - rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION); - - dict_foreign_err_file = os_file_create_tmpfile(); - ut_a(dict_foreign_err_file); - mutex_create(&dict_foreign_err_mutex); - mutex_set_level(&dict_foreign_err_mutex, SYNC_ANY_LATCH); -} - -/************************************************************************** -Returns a table object and memoryfixes it. NOTE! This is a high-level -function to be used mainly from outside the 'dict' directory. Inside this -directory dict_table_get_low is usually the appropriate function. */ - -dict_table_t* -dict_table_get( -/*===========*/ - /* out: table, NULL if - does not exist */ - const char* table_name, /* in: table name */ - trx_t* trx) /* in: transaction handle or NULL */ -{ - dict_table_t* table; - - UT_NOT_USED(trx); - - mutex_enter(&(dict_sys->mutex)); - - table = dict_table_get_low(table_name); - - mutex_exit(&(dict_sys->mutex)); - - if (table != NULL) { - if (!table->stat_initialized) { - dict_update_statistics(table); - } - } - - return(table); -} - -/************************************************************************** -Returns a table object and increments MySQL open handle count on the table. */ - -dict_table_t* -dict_table_get_and_increment_handle_count( -/*======================================*/ - /* out: table, NULL if - does not exist */ - const char* table_name, /* in: table name */ - trx_t* trx) /* in: transaction handle or NULL */ -{ - dict_table_t* table; - - UT_NOT_USED(trx); - - mutex_enter(&(dict_sys->mutex)); - - table = dict_table_get_low(table_name); - - if (table != NULL) { - - table->n_mysql_handles_opened++; - } - - mutex_exit(&(dict_sys->mutex)); - - if (table != NULL) { - if (!table->stat_initialized && !table->ibd_file_missing) { - dict_update_statistics(table); - } - } - - return(table); -} - -/************************************************************************** -Adds a table object to the dictionary cache. */ - -void -dict_table_add_to_cache( -/*====================*/ - dict_table_t* table) /* in: table */ -{ - ulint fold; - ulint id_fold; - ulint i; - - ut_ad(table); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS); - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - ut_ad(table->cached == FALSE); - - fold = ut_fold_string(table->name); - id_fold = ut_fold_dulint(table->id); - - table->cached = TRUE; - - /* NOTE: the system columns MUST be added in the following order - (so that they can be indexed by the numerical value of DATA_ROW_ID, - etc.) and as the last columns of the table memory object. - The clustered index will not always physically contain all - system columns. */ - - dict_mem_table_add_col(table, "DB_ROW_ID", DATA_SYS, - DATA_ROW_ID | DATA_NOT_NULL, DATA_ROW_ID_LEN, 0); -#if DATA_ROW_ID != 0 -#error "DATA_ROW_ID != 0" -#endif - dict_mem_table_add_col(table, "DB_TRX_ID", DATA_SYS, - DATA_TRX_ID | DATA_NOT_NULL, DATA_TRX_ID_LEN, 0); -#if DATA_TRX_ID != 1 -#error "DATA_TRX_ID != 1" -#endif - dict_mem_table_add_col(table, "DB_ROLL_PTR", DATA_SYS, - DATA_ROLL_PTR | DATA_NOT_NULL, DATA_ROLL_PTR_LEN, 0); -#if DATA_ROLL_PTR != 2 -#error "DATA_ROLL_PTR != 2" -#endif - dict_mem_table_add_col(table, "DB_MIX_ID", DATA_SYS, - DATA_MIX_ID | DATA_NOT_NULL, DATA_MIX_ID_LEN, 0); -#if DATA_MIX_ID != 3 -#error "DATA_MIX_ID != 3" -#endif - - /* This check reminds that if a new system column is added to - the program, it should be dealt with here */ -#if DATA_N_SYS_COLS != 4 -#error "DATA_N_SYS_COLS != 4" -#endif - - /* Look for a table with the same name: error if such exists */ - { - dict_table_t* table2; - HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2, - (ut_strcmp(table2->name, table->name) == 0)); - ut_a(table2 == NULL); - } - - /* Look for a table with the same id: error if such exists */ - { - dict_table_t* table2; - HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold, table2, - (ut_dulint_cmp(table2->id, table->id) == 0)); - ut_a(table2 == NULL); - } - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - table->mix_id_len = mach_dulint_get_compressed_size( - table->mix_id); - mach_dulint_write_compressed(table->mix_id_buf, table->mix_id); - } - - /* Add the columns to the column hash table */ - for (i = 0; i < table->n_cols; i++) { - dict_col_add_to_cache(table, dict_table_get_nth_col(table, i)); - } - - /* Add table to hash table of tables */ - HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, - table); - - /* Add table to hash table of tables based on table id */ - HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold, - table); - /* Add table to LRU list of tables */ - UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table); - - /* If the dictionary cache grows too big, trim the table LRU list */ - - dict_sys->size += mem_heap_get_size(table->heap); - /* dict_table_LRU_trim(); */ -} - -/************************************************************************** -Looks for an index with the given id. NOTE that we do not reserve -the dictionary mutex: this function is for emergency purposes like -printing info of a corrupt database page! */ - -dict_index_t* -dict_index_find_on_id_low( -/*======================*/ - /* out: index or NULL if not found from cache */ - dulint id) /* in: index id */ -{ - dict_table_t* table; - dict_index_t* index; - - table = UT_LIST_GET_FIRST(dict_sys->table_LRU); - - while (table) { - index = dict_table_get_first_index(table); - - while (index) { - if (0 == ut_dulint_cmp(id, index->tree->id)) { - /* Found */ - - return(index); - } - - index = dict_table_get_next_index(index); - } - - table = UT_LIST_GET_NEXT(table_LRU, table); - } - - return(NULL); -} - -/************************************************************************** -Renames a table object. */ - -ibool -dict_table_rename_in_cache( -/*=======================*/ - /* out: TRUE if success */ - dict_table_t* table, /* in: table */ - const char* new_name, /* in: new name */ - ibool rename_also_foreigns)/* in: in ALTER TABLE we want - to preserve the original table name - in constraints which reference it */ -{ - dict_foreign_t* foreign; - dict_index_t* index; - ulint fold; - ulint old_size; - char* old_name; - ibool success; - ulint i; - - ut_ad(table); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - old_size = mem_heap_get_size(table->heap); - - fold = ut_fold_string(new_name); - - /* Look for a table with the same name: error if such exists */ - { - dict_table_t* table2; - HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2, - (ut_strcmp(table2->name, new_name) == 0)); - if (table2) { - fprintf(stderr, -"InnoDB: Error: dictionary cache already contains a table of name %s\n", - new_name); - return(FALSE); - } - } - - /* If the table is stored in a single-table tablespace, rename the - .ibd file */ - - if (table->space != 0) { - if (table->dir_path_of_temp_table != NULL) { - fprintf(stderr, -"InnoDB: Error: trying to rename a table %s (%s) created with CREATE\n" -"InnoDB: TEMPORARY TABLE\n", table->name, table->dir_path_of_temp_table); - success = FALSE; - } else { - success = fil_rename_tablespace(table->name, - table->space, new_name); - } - - if (!success) { - - return(FALSE); - } - } - - /* Reposition the columns in the column hash table; they are hashed - according to the pair (table name, column name) */ - - for (i = 0; i < table->n_cols; i++) { - dict_col_reposition_in_cache(table, - dict_table_get_nth_col(table, i), new_name); - } - - /* Remove table from the hash tables of tables */ - HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, - ut_fold_string(table->name), table); - old_name = mem_heap_strdup(table->heap, table->name); - table->name = mem_heap_strdup(table->heap, new_name); - - /* Add table to hash table of tables */ - HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, - table); - dict_sys->size += (mem_heap_get_size(table->heap) - old_size); - - /* Update the table_name field in indexes */ - index = dict_table_get_first_index(table); - - while (index != NULL) { - index->table_name = table->name; - - index = dict_table_get_next_index(index); - } - - if (!rename_also_foreigns) { - /* In ALTER TABLE we think of the rename table operation - in the direction table -> temporary table (#sql...) - as dropping the table with the old name and creating - a new with the new name. Thus we kind of drop the - constraints from the dictionary cache here. The foreign key - constraints will be inherited to the new table from the - system tables through a call of dict_load_foreigns. */ - - /* Remove the foreign constraints from the cache */ - foreign = UT_LIST_GET_LAST(table->foreign_list); - - while (foreign != NULL) { - dict_foreign_remove_from_cache(foreign); - foreign = UT_LIST_GET_LAST(table->foreign_list); - } - - /* Reset table field in referencing constraints */ - - foreign = UT_LIST_GET_FIRST(table->referenced_list); - - while (foreign != NULL) { - foreign->referenced_table = NULL; - foreign->referenced_index = NULL; - - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); - } - - /* Make the list of referencing constraints empty */ - - UT_LIST_INIT(table->referenced_list); - - return(TRUE); - } - - /* Update the table name fields in foreign constraints, and update also - the constraint id of new format >= 4.0.18 constraints. Note that at - this point we have already changed table->name to the new name. */ - - foreign = UT_LIST_GET_FIRST(table->foreign_list); - - while (foreign != NULL) { - if (ut_strlen(foreign->foreign_table_name) < - ut_strlen(table->name)) { - /* Allocate a longer name buffer; - TODO: store buf len to save memory */ - - foreign->foreign_table_name = mem_heap_alloc( - foreign->heap, - ut_strlen(table->name) + 1); - } - - strcpy(foreign->foreign_table_name, table->name); - - if (strchr(foreign->id, '/')) { - ulint db_len; - char* old_id; - - /* This is a >= 4.0.18 format id */ - - old_id = mem_strdup(foreign->id); - - if (ut_strlen(foreign->id) > ut_strlen(old_name) - + ((sizeof dict_ibfk) - 1) - && 0 == ut_memcmp(foreign->id, old_name, - ut_strlen(old_name)) - && 0 == ut_memcmp( - foreign->id + ut_strlen(old_name), - dict_ibfk, (sizeof dict_ibfk) - 1)) { - - /* This is a generated >= 4.0.18 format id */ - - if (ut_strlen(table->name) > ut_strlen(old_name)) { - foreign->id = mem_heap_alloc( - foreign->heap, - ut_strlen(table->name) - + ut_strlen(old_id) + 1); - } - - /* Replace the prefix 'databasename/tablename' - with the new names */ - strcpy(foreign->id, table->name); - strcat(foreign->id, - old_id + ut_strlen(old_name)); - } else { - /* This is a >= 4.0.18 format id where the user - gave the id name */ - db_len = dict_get_db_name_len(table->name) + 1; - - if (dict_get_db_name_len(table->name) - > dict_get_db_name_len(foreign->id)) { - - foreign->id = mem_heap_alloc( - foreign->heap, - db_len + ut_strlen(old_id) + 1); - } - - /* Replace the database prefix in id with the - one from table->name */ - - ut_memcpy(foreign->id, table->name, db_len); - - strcpy(foreign->id + db_len, - dict_remove_db_name(old_id)); - } - - mem_free(old_id); - } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } - - foreign = UT_LIST_GET_FIRST(table->referenced_list); - - while (foreign != NULL) { - if (ut_strlen(foreign->referenced_table_name) < - ut_strlen(table->name)) { - /* Allocate a longer name buffer; - TODO: store buf len to save memory */ - - foreign->referenced_table_name = mem_heap_alloc( - foreign->heap, - ut_strlen(table->name) + 1); - } - - strcpy(foreign->referenced_table_name, table->name); - - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); - } - - return(TRUE); -} - -/************************************************************************** -Change the id of a table object in the dictionary cache. This is used in -DISCARD TABLESPACE. */ - -void -dict_table_change_id_in_cache( -/*==========================*/ - dict_table_t* table, /* in: table object already in cache */ - dulint new_id) /* in: new id to set */ -{ - ut_ad(table); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - /* Remove the table from the hash table of id's */ - - HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash, - ut_fold_dulint(table->id), table); - table->id = new_id; - - /* Add the table back to the hash table */ - HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, - ut_fold_dulint(table->id), table); -} - -/************************************************************************** -Removes a table object from the dictionary cache. */ - -void -dict_table_remove_from_cache( -/*=========================*/ - dict_table_t* table) /* in, own: table */ -{ - dict_foreign_t* foreign; - dict_index_t* index; - ulint size; - ulint i; - - ut_ad(table); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - -#if 0 - fputs("Removing table ", stderr); - ut_print_name(stderr, table->name, ULINT_UNDEFINED); - fputs(" from dictionary cache\n", stderr); -#endif - - /* Remove the foreign constraints from the cache */ - foreign = UT_LIST_GET_LAST(table->foreign_list); - - while (foreign != NULL) { - dict_foreign_remove_from_cache(foreign); - foreign = UT_LIST_GET_LAST(table->foreign_list); - } - - /* Reset table field in referencing constraints */ - - foreign = UT_LIST_GET_FIRST(table->referenced_list); - - while (foreign != NULL) { - foreign->referenced_table = NULL; - foreign->referenced_index = NULL; - - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); - } - - /* Remove the indexes from the cache */ - index = UT_LIST_GET_LAST(table->indexes); - - while (index != NULL) { - dict_index_remove_from_cache(table, index); - index = UT_LIST_GET_LAST(table->indexes); - } - - /* Remove the columns of the table from the cache */ - for (i = 0; i < table->n_cols; i++) { - dict_col_remove_from_cache(table, - dict_table_get_nth_col(table, i)); - } - - /* Remove table from the hash tables of tables */ - HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, - ut_fold_string(table->name), table); - HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash, - ut_fold_dulint(table->id), table); - - /* Remove table from LRU list of tables */ - UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table); - - mutex_free(&(table->autoinc_mutex)); - - size = mem_heap_get_size(table->heap); - - ut_ad(dict_sys->size >= size); - - dict_sys->size -= size; - - mem_heap_free(table->heap); -} - -/************************************************************************** -Frees tables from the end of table_LRU if the dictionary cache occupies -too much space. Currently not used! */ - -void -dict_table_LRU_trim(void) -/*=====================*/ -{ - dict_table_t* table; - dict_table_t* prev_table; - - ut_error; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - table = UT_LIST_GET_LAST(dict_sys->table_LRU); - - while (table && (dict_sys->size > - buf_pool_get_max_size() / DICT_POOL_PER_VARYING)) { - - prev_table = UT_LIST_GET_PREV(table_LRU, table); - - if (table->mem_fix == 0) { - dict_table_remove_from_cache(table); - } - - table = prev_table; - } -} - -/************************************************************************** -Adds a column to the data dictionary hash table. */ -static -void -dict_col_add_to_cache( -/*==================*/ - dict_table_t* table, /* in: table */ - dict_col_t* col) /* in: column */ -{ - ulint fold; - - ut_ad(table && col); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - fold = ut_fold_ulint_pair(ut_fold_string(table->name), - ut_fold_string(col->name)); - - /* Look for a column with same table name and column name: error */ - { - dict_col_t* col2; - HASH_SEARCH(hash, dict_sys->col_hash, fold, col2, - (ut_strcmp(col->name, col2->name) == 0) - && (ut_strcmp((col2->table)->name, table->name) - == 0)); - ut_a(col2 == NULL); - } - - HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col); -} - -/************************************************************************** -Removes a column from the data dictionary hash table. */ -static -void -dict_col_remove_from_cache( -/*=======================*/ - dict_table_t* table, /* in: table */ - dict_col_t* col) /* in: column */ -{ - ulint fold; - - ut_ad(table && col); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - fold = ut_fold_ulint_pair(ut_fold_string(table->name), - ut_fold_string(col->name)); - - HASH_DELETE(dict_col_t, hash, dict_sys->col_hash, fold, col); -} - -/************************************************************************** -Repositions a column in the data dictionary hash table when the table name -changes. */ -static -void -dict_col_reposition_in_cache( -/*=========================*/ - dict_table_t* table, /* in: table */ - dict_col_t* col, /* in: column */ - const char* new_name) /* in: new table name */ -{ - ulint fold; - - ut_ad(table && col); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - fold = ut_fold_ulint_pair(ut_fold_string(table->name), - ut_fold_string(col->name)); - - HASH_DELETE(dict_col_t, hash, dict_sys->col_hash, fold, col); - - fold = ut_fold_ulint_pair(ut_fold_string(new_name), - ut_fold_string(col->name)); - - HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col); -} - -/************************************************************************** -Adds an index to the dictionary cache. */ - -ibool -dict_index_add_to_cache( -/*====================*/ - /* out: TRUE if success */ - dict_table_t* table, /* in: table on which the index is */ - dict_index_t* index, /* in, own: index; NOTE! The index memory - object is freed in this function! */ - ulint page_no)/* in: root page number of the index */ -{ - dict_index_t* new_index; - dict_tree_t* tree; - dict_table_t* cluster; - dict_field_t* field; - ulint n_ord; - ibool success; - ulint i; - - ut_ad(index); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(index->n_def == index->n_fields); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - - ut_ad(mem_heap_validate(index->heap)); - - { - dict_index_t* index2; - index2 = UT_LIST_GET_FIRST(table->indexes); - - while (index2 != NULL) { - ut_ad(ut_strcmp(index->name, index2->name) != 0); - - index2 = UT_LIST_GET_NEXT(indexes, index2); - } - - ut_a(UT_LIST_GET_LEN(table->indexes) == 0 - || (index->type & DICT_CLUSTERED) == 0); - } - - success = dict_index_find_cols(table, index); - - if (!success) { - dict_mem_index_free(index); - - return(FALSE); - } - - /* Build the cache internal representation of the index, - containing also the added system fields */ - - if (index->type & DICT_CLUSTERED) { - new_index = dict_index_build_internal_clust(table, index); - } else { - new_index = dict_index_build_internal_non_clust(table, index); - } - - new_index->search_info = btr_search_info_create(new_index->heap); - - /* Set the n_fields value in new_index to the actual defined - number of fields in the cache internal representation */ - - new_index->n_fields = new_index->n_def; - - /* Add the new index as the last index for the table */ - - UT_LIST_ADD_LAST(indexes, table->indexes, new_index); - new_index->table = table; - new_index->table_name = table->name; - - /* Increment the ord_part counts in columns which are ordering */ - - if (index->type & DICT_UNIVERSAL) { - n_ord = new_index->n_fields; - } else { - n_ord = dict_index_get_n_unique(new_index); - } - - for (i = 0; i < n_ord; i++) { - - field = dict_index_get_nth_field(new_index, i); - - dict_field_get_col(field)->ord_part++; - } - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - /* The index tree is found from the cluster object */ - - cluster = dict_table_get_low(table->cluster_name); - - tree = dict_index_get_tree( - UT_LIST_GET_FIRST(cluster->indexes)); - new_index->tree = tree; - } else { - /* Create an index tree memory object for the index */ - tree = dict_tree_create(new_index, page_no); - ut_ad(tree); - - new_index->tree = tree; - } - - if (!(new_index->type & DICT_UNIVERSAL)) { - - new_index->stat_n_diff_key_vals = - mem_heap_alloc(new_index->heap, - (1 + dict_index_get_n_unique(new_index)) - * sizeof(ib_longlong)); - /* Give some sensible values to stat_n_... in case we do - not calculate statistics quickly enough */ - - for (i = 0; i <= dict_index_get_n_unique(new_index); i++) { - - new_index->stat_n_diff_key_vals[i] = 100; - } - } - - /* Add the index to the list of indexes stored in the tree */ - UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index); - - /* If the dictionary cache grows too big, trim the table LRU list */ - - dict_sys->size += mem_heap_get_size(new_index->heap); - /* dict_table_LRU_trim(); */ - - dict_mem_index_free(index); - - return(TRUE); -} - -/************************************************************************** -Removes an index from the dictionary cache. */ -static -void -dict_index_remove_from_cache( -/*=========================*/ - dict_table_t* table, /* in: table */ - dict_index_t* index) /* in, own: index */ -{ - dict_field_t* field; - ulint size; - ulint i; - - ut_ad(table && index); - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - ut_ad(UT_LIST_GET_LEN((index->tree)->tree_indexes) == 1); - dict_tree_free(index->tree); - - /* Decrement the ord_part counts in columns which are ordering */ - for (i = 0; i < dict_index_get_n_unique(index); i++) { - - field = dict_index_get_nth_field(index, i); - - ut_ad(dict_field_get_col(field)->ord_part > 0); - (dict_field_get_col(field)->ord_part)--; - } - - /* Remove the index from the list of indexes of the table */ - UT_LIST_REMOVE(indexes, table->indexes, index); - - size = mem_heap_get_size(index->heap); - - ut_ad(dict_sys->size >= size); - - dict_sys->size -= size; - - mem_heap_free(index->heap); -} - -/*********************************************************************** -Tries to find column names for the index in the column hash table and -sets the col field of the index. */ -static -ibool -dict_index_find_cols( -/*=================*/ - /* out: TRUE if success */ - dict_table_t* table, /* in: table */ - dict_index_t* index) /* in: index */ -{ - dict_col_t* col; - dict_field_t* field; - ulint fold; - ulint i; - - ut_ad(table && index); - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - for (i = 0; i < index->n_fields; i++) { - field = dict_index_get_nth_field(index, i); - - fold = ut_fold_ulint_pair(ut_fold_string(table->name), - ut_fold_string(field->name)); - - HASH_SEARCH(hash, dict_sys->col_hash, fold, col, - (ut_strcmp(col->name, field->name) == 0) - && (ut_strcmp((col->table)->name, table->name) - == 0)); - if (col == NULL) { - - return(FALSE); - } else { - field->col = col; - } - } - - return(TRUE); -} - -/*********************************************************************** -Adds a column to index. */ - -void -dict_index_add_col( -/*===============*/ - dict_index_t* index, /* in: index */ - dict_col_t* col, /* in: column */ - ulint order, /* in: order criterion */ - ulint prefix_len) /* in: column prefix length */ -{ - dict_field_t* field; - - dict_mem_index_add_field(index, col->name, order, prefix_len); - - field = dict_index_get_nth_field(index, index->n_def - 1); - - field->col = col; - field->fixed_len = dtype_get_fixed_size(&col->type); - - if (prefix_len && field->fixed_len > prefix_len) { - field->fixed_len = prefix_len; - } - - /* Long fixed-length fields that need external storage are treated as - variable-length fields, so that the extern flag can be embedded in - the length word. */ - - if (field->fixed_len > DICT_MAX_COL_PREFIX_LEN) { - field->fixed_len = 0; - } - - if (!(dtype_get_prtype(&col->type) & DATA_NOT_NULL)) { - index->n_nullable++; - } - - if (index->n_def > 1) { - const dict_field_t* field2 = - dict_index_get_nth_field(index, index->n_def - 2); - field->fixed_offs = (!field2->fixed_len || - field2->fixed_offs == ULINT_UNDEFINED) - ? ULINT_UNDEFINED - : field2->fixed_len + field2->fixed_offs; - } else { - field->fixed_offs = 0; - } -} - -/*********************************************************************** -Copies fields contained in index2 to index1. */ -static -void -dict_index_copy( -/*============*/ - dict_index_t* index1, /* in: index to copy to */ - dict_index_t* index2, /* in: index to copy from */ - ulint start, /* in: first position to copy */ - ulint end) /* in: last position to copy */ -{ - dict_field_t* field; - ulint i; - - /* Copy fields contained in index2 */ - - for (i = start; i < end; i++) { - - field = dict_index_get_nth_field(index2, i); - dict_index_add_col(index1, field->col, field->order, - field->prefix_len); - } -} - -/*********************************************************************** -Copies types of fields contained in index to tuple. */ - -void -dict_index_copy_types( -/*==================*/ - dtuple_t* tuple, /* in: data tuple */ - dict_index_t* index, /* in: index */ - ulint n_fields) /* in: number of field types to copy */ -{ - dtype_t* dfield_type; - dtype_t* type; - ulint i; - - if (index->type & DICT_UNIVERSAL) { - dtuple_set_types_binary(tuple, n_fields); - - return; - } - - for (i = 0; i < n_fields; i++) { - dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i)); - type = dict_col_get_type(dict_field_get_col( - dict_index_get_nth_field(index, i))); - *dfield_type = *type; - } -} - -/*********************************************************************** -Copies types of columns contained in table to tuple. */ - -void -dict_table_copy_types( -/*==================*/ - dtuple_t* tuple, /* in: data tuple */ - dict_table_t* table) /* in: index */ -{ - dtype_t* dfield_type; - dtype_t* type; - ulint i; - - ut_ad(!(table->type & DICT_UNIVERSAL)); - - for (i = 0; i < dtuple_get_n_fields(tuple); i++) { - - dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i)); - type = dict_col_get_type(dict_table_get_nth_col(table, i)); - - *dfield_type = *type; - } -} - -/*********************************************************************** -Builds the internal dictionary cache representation for a clustered -index, containing also system fields not defined by the user. */ -static -dict_index_t* -dict_index_build_internal_clust( -/*============================*/ - /* out, own: the internal representation - of the clustered index */ - dict_table_t* table, /* in: table */ - dict_index_t* index) /* in: user representation of a clustered - index */ -{ - dict_index_t* new_index; - dict_field_t* field; - dict_col_t* col; - ulint fixed_size; - ulint trx_id_pos; - ulint i; - - ut_ad(table && index); - ut_ad(index->type & DICT_CLUSTERED); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - /* Create a new index object with certainly enough fields */ - new_index = dict_mem_index_create(table->name, - index->name, - table->space, - index->type, - index->n_fields + table->n_cols); - - /* Copy other relevant data from the old index struct to the new - struct: it inherits the values */ - - new_index->n_user_defined_cols = index->n_fields; - - new_index->id = index->id; - - if (table->type != DICT_TABLE_ORDINARY) { - /* The index is mixed: copy common key prefix fields */ - - dict_index_copy(new_index, index, 0, table->mix_len); - - /* Add the mix id column */ - dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_MIX_ID), 0, 0); - - /* Copy the rest of fields */ - dict_index_copy(new_index, index, table->mix_len, - index->n_fields); - } else { - /* Copy the fields of index */ - dict_index_copy(new_index, index, 0, index->n_fields); - } - - if (index->type & DICT_UNIVERSAL) { - /* No fixed number of fields determines an entry uniquely */ - - new_index->n_uniq = ULINT_MAX; - - } else if (index->type & DICT_UNIQUE) { - /* Only the fields defined so far are needed to identify - the index entry uniquely */ - - new_index->n_uniq = new_index->n_def; - } else { - /* Also the row id is needed to identify the entry */ - new_index->n_uniq = 1 + new_index->n_def; - } - - new_index->trx_id_offset = 0; - - if (!(index->type & DICT_IBUF)) { - /* Add system columns, trx id first */ - - trx_id_pos = new_index->n_def; - - ut_ad(DATA_ROW_ID == 0); - ut_ad(DATA_TRX_ID == 1); - ut_ad(DATA_ROLL_PTR == 2); - - if (!(index->type & DICT_UNIQUE)) { - dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_ROW_ID), 0, 0); - trx_id_pos++; - } - - dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_TRX_ID), 0, 0); - - dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_ROLL_PTR), 0, 0); - - for (i = 0; i < trx_id_pos; i++) { - - fixed_size = dtype_get_fixed_size( - dict_index_get_nth_type(new_index, i)); - - if (fixed_size == 0) { - new_index->trx_id_offset = 0; - - break; - } - - if (dict_index_get_nth_field(new_index, i)->prefix_len - > 0) { - new_index->trx_id_offset = 0; - - break; - } - - new_index->trx_id_offset += fixed_size; - } - - } - - /* Set auxiliary variables in table columns as undefined */ - for (i = 0; i < table->n_cols; i++) { - - col = dict_table_get_nth_col(table, i); - col->aux = ULINT_UNDEFINED; - } - - /* Mark with 0 the table columns already contained in new_index */ - for (i = 0; i < new_index->n_def; i++) { - - field = dict_index_get_nth_field(new_index, i); - - /* If there is only a prefix of the column in the index - field, do not mark the column as contained in the index */ - - if (field->prefix_len == 0) { - - field->col->aux = 0; - } - } - - /* Add to new_index non-system columns of table not yet included - there */ - for (i = 0; i < table->n_cols - DATA_N_SYS_COLS; i++) { - - col = dict_table_get_nth_col(table, i); - ut_ad(col->type.mtype != DATA_SYS); - - if (col->aux == ULINT_UNDEFINED) { - dict_index_add_col(new_index, col, 0, 0); - } - } - - ut_ad((index->type & DICT_IBUF) - || (UT_LIST_GET_LEN(table->indexes) == 0)); - - /* Store to the column structs the position of the table columns - in the clustered index */ - - for (i = 0; i < new_index->n_def; i++) { - field = dict_index_get_nth_field(new_index, i); - - if (field->prefix_len == 0) { - - field->col->clust_pos = i; - } - } - - new_index->cached = TRUE; - - return(new_index); -} - -/*********************************************************************** -Builds the internal dictionary cache representation for a non-clustered -index, containing also system fields not defined by the user. */ -static -dict_index_t* -dict_index_build_internal_non_clust( -/*================================*/ - /* out, own: the internal representation - of the non-clustered index */ - dict_table_t* table, /* in: table */ - dict_index_t* index) /* in: user representation of a non-clustered - index */ -{ - dict_field_t* field; - dict_index_t* new_index; - dict_index_t* clust_index; - ulint i; - - ut_ad(table && index); - ut_ad(0 == (index->type & DICT_CLUSTERED)); -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - /* The clustered index should be the first in the list of indexes */ - clust_index = UT_LIST_GET_FIRST(table->indexes); - - ut_ad(clust_index); - ut_ad(clust_index->type & DICT_CLUSTERED); - ut_ad(!(clust_index->type & DICT_UNIVERSAL)); - - /* Create a new index */ - new_index = dict_mem_index_create(table->name, - index->name, - index->space, - index->type, - index->n_fields - + 1 + clust_index->n_uniq); - - /* Copy other relevant data from the old index - struct to the new struct: it inherits the values */ - - new_index->n_user_defined_cols = index->n_fields; - - new_index->id = index->id; - - /* Copy fields from index to new_index */ - dict_index_copy(new_index, index, 0, index->n_fields); - - /* Set the auxiliary variables in the clust_index unique columns - as undefined */ - for (i = 0; i < clust_index->n_uniq; i++) { - - field = dict_index_get_nth_field(clust_index, i); - field->col->aux = ULINT_UNDEFINED; - } - - /* Mark with 0 table columns already contained in new_index */ - for (i = 0; i < new_index->n_def; i++) { - - field = dict_index_get_nth_field(new_index, i); - - /* If there is only a prefix of the column in the index - field, do not mark the column as contained in the index */ - - if (field->prefix_len == 0) { - - field->col->aux = 0; - } - } - - /* Add to new_index the columns necessary to determine the clustered - index entry uniquely */ - - for (i = 0; i < clust_index->n_uniq; i++) { - - field = dict_index_get_nth_field(clust_index, i); - - if (field->col->aux == ULINT_UNDEFINED) { - dict_index_add_col(new_index, field->col, 0, - field->prefix_len); - } - } - - if ((index->type) & DICT_UNIQUE) { - new_index->n_uniq = index->n_fields; - } else { - new_index->n_uniq = new_index->n_def; - } - - /* Set the n_fields value in new_index to the actual defined - number of fields */ - - new_index->n_fields = new_index->n_def; - - new_index->cached = TRUE; - - return(new_index); -} - -/*====================== FOREIGN KEY PROCESSING ========================*/ - -/************************************************************************* -Checks if a table is referenced by foreign keys. */ - -ibool -dict_table_referenced_by_foreign_key( -/*=================================*/ - /* out: TRUE if table is referenced by a - foreign key */ - dict_table_t* table) /* in: InnoDB table */ -{ - if (UT_LIST_GET_LEN(table->referenced_list) > 0) { - - return(TRUE); - } - - return(FALSE); -} - -/************************************************************************* -Frees a foreign key struct. */ -static -void -dict_foreign_free( -/*==============*/ - dict_foreign_t* foreign) /* in, own: foreign key struct */ -{ - mem_heap_free(foreign->heap); -} - -/************************************************************************** -Removes a foreign constraint struct from the dictionary cache. */ -static -void -dict_foreign_remove_from_cache( -/*===========================*/ - dict_foreign_t* foreign) /* in, own: foreign constraint */ -{ -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - ut_a(foreign); - - if (foreign->referenced_table) { - UT_LIST_REMOVE(referenced_list, - foreign->referenced_table->referenced_list, foreign); - } - - if (foreign->foreign_table) { - UT_LIST_REMOVE(foreign_list, - foreign->foreign_table->foreign_list, foreign); - } - - dict_foreign_free(foreign); -} - -/************************************************************************** -Looks for the foreign constraint from the foreign and referenced lists -of a table. */ -static -dict_foreign_t* -dict_foreign_find( -/*==============*/ - /* out: foreign constraint */ - dict_table_t* table, /* in: table object */ - const char* id) /* in: foreign constraint id */ -{ - dict_foreign_t* foreign; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - foreign = UT_LIST_GET_FIRST(table->foreign_list); - - while (foreign) { - if (ut_strcmp(id, foreign->id) == 0) { - - return(foreign); - } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } - - foreign = UT_LIST_GET_FIRST(table->referenced_list); - - while (foreign) { - if (ut_strcmp(id, foreign->id) == 0) { - - return(foreign); - } - - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); - } - - return(NULL); -} - -/************************************************************************* -Tries to find an index whose first fields are the columns in the array, -in the same order. */ -static -dict_index_t* -dict_foreign_find_index( -/*====================*/ - /* out: matching index, NULL if not found */ - dict_table_t* table, /* in: table */ - const char** columns,/* in: array of column names */ - ulint n_cols, /* in: number of columns */ - dict_index_t* types_idx)/* in: NULL or an index to whose types the - column types must match */ -{ -#ifndef UNIV_HOTBACKUP - dict_index_t* index; - const char* col_name; - ulint i; - - index = dict_table_get_first_index(table); - - while (index != NULL) { - if (dict_index_get_n_fields(index) >= n_cols) { - - for (i = 0; i < n_cols; i++) { - col_name = dict_index_get_nth_field(index, i) - ->col->name; - if (dict_index_get_nth_field(index, i) - ->prefix_len != 0) { - /* We do not accept column prefix - indexes here */ - - break; - } - - if (0 != innobase_strcasecmp(columns[i], - col_name)) { - break; - } - - if (types_idx && !cmp_types_are_equal( - dict_index_get_nth_type(index, i), - dict_index_get_nth_type(types_idx, i))) { - - break; - } - } - - if (i == n_cols) { - /* We found a matching index */ - - return(index); - } - } - - index = dict_table_get_next_index(index); - } - - return(NULL); -#else /* UNIV_HOTBACKUP */ - /* This function depends on MySQL code that is not included in - InnoDB Hot Backup builds. Besides, this function should never - be called in InnoDB Hot Backup. */ - ut_error; -#endif /* UNIV_HOTBACKUP */ -} - -/************************************************************************** -Report an error in a foreign key definition. */ -static -void -dict_foreign_error_report_low( -/*==========================*/ - FILE* file, /* in: output stream */ - const char* name) /* in: table name */ -{ - rewind(file); - ut_print_timestamp(file); - fprintf(file, " Error in foreign key constraint of table %s:\n", - name); -} - -/************************************************************************** -Report an error in a foreign key definition. */ -static -void -dict_foreign_error_report( -/*======================*/ - FILE* file, /* in: output stream */ - dict_foreign_t* fk, /* in: foreign key constraint */ - const char* msg) /* in: the error message */ -{ - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(file, fk->foreign_table_name); - fputs(msg, file); - fputs(" Constraint:\n", file); - dict_print_info_on_foreign_key_in_create_format(file, NULL, fk); - if (fk->foreign_index) { - fputs("\nThe index in the foreign key in table is ", file); - ut_print_name(file, NULL, fk->foreign_index->name); - fputs( -"\nSee http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" -"for correct foreign key definition.\n", - file); - } - mutex_exit(&dict_foreign_err_mutex); -} - -/************************************************************************** -Adds a foreign key constraint object to the dictionary cache. May free -the object if there already is an object with the same identifier in. -At least one of the foreign table and the referenced table must already -be in the dictionary cache! */ - -ulint -dict_foreign_add_to_cache( -/*======================*/ - /* out: DB_SUCCESS or error code */ - dict_foreign_t* foreign) /* in, own: foreign key constraint */ -{ - dict_table_t* for_table; - dict_table_t* ref_table; - dict_foreign_t* for_in_cache = NULL; - dict_index_t* index; - ibool added_to_referenced_list= FALSE; - FILE* ef = dict_foreign_err_file; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - for_table = dict_table_check_if_in_cache_low( - foreign->foreign_table_name); - - ref_table = dict_table_check_if_in_cache_low( - foreign->referenced_table_name); - ut_a(for_table || ref_table); - - if (for_table) { - for_in_cache = dict_foreign_find(for_table, foreign->id); - } - - if (!for_in_cache && ref_table) { - for_in_cache = dict_foreign_find(ref_table, foreign->id); - } - - if (for_in_cache) { - /* Free the foreign object */ - mem_heap_free(foreign->heap); - } else { - for_in_cache = foreign; - } - - if (for_in_cache->referenced_table == NULL && ref_table) { - index = dict_foreign_find_index(ref_table, - (const char**) for_in_cache->referenced_col_names, - for_in_cache->n_fields, - for_in_cache->foreign_index); - - if (index == NULL) { - dict_foreign_error_report(ef, for_in_cache, -"there is no index in referenced table which would contain\n" -"the columns as the first columns, or the data types in the\n" -"referenced table do not match to the ones in table."); - - if (for_in_cache == foreign) { - mem_heap_free(foreign->heap); - } - - return(DB_CANNOT_ADD_CONSTRAINT); - } - - for_in_cache->referenced_table = ref_table; - for_in_cache->referenced_index = index; - UT_LIST_ADD_LAST(referenced_list, - ref_table->referenced_list, - for_in_cache); - added_to_referenced_list = TRUE; - } - - if (for_in_cache->foreign_table == NULL && for_table) { - index = dict_foreign_find_index(for_table, - (const char**) for_in_cache->foreign_col_names, - for_in_cache->n_fields, - for_in_cache->referenced_index); - - if (index == NULL) { - dict_foreign_error_report(ef, for_in_cache, -"there is no index in the table which would contain\n" -"the columns as the first columns, or the data types in the\n" -"table do not match to the ones in the referenced table."); - - if (for_in_cache == foreign) { - if (added_to_referenced_list) { - UT_LIST_REMOVE(referenced_list, - ref_table->referenced_list, - for_in_cache); - } - - mem_heap_free(foreign->heap); - } - - return(DB_CANNOT_ADD_CONSTRAINT); - } - - for_in_cache->foreign_table = for_table; - for_in_cache->foreign_index = index; - UT_LIST_ADD_LAST(foreign_list, - for_table->foreign_list, - for_in_cache); - } - - return(DB_SUCCESS); -} - -/************************************************************************* -Scans from pointer onwards. Stops if is at the start of a copy of -'string' where characters are compared without case sensitivity, and -only outside `` or "" quotes. Stops also at '\0'. */ - -const char* -dict_scan_to( -/*=========*/ - /* out: scanned up to this */ - const char* ptr, /* in: scan from */ - const char* string) /* in: look for this */ -{ - char quote = '\0'; - - for (; *ptr; ptr++) { - if (*ptr == quote) { - /* Closing quote character: do not look for - starting quote or the keyword. */ - quote = '\0'; - } else if (quote) { - /* Within quotes: do nothing. */ - } else if (*ptr == '`' || *ptr == '"') { - /* Starting quote: remember the quote character. */ - quote = *ptr; - } else { - /* Outside quotes: look for the keyword. */ - ulint i; - for (i = 0; string[i]; i++) { - if (toupper((int)(unsigned char)(ptr[i])) - != toupper((int)(unsigned char) - (string[i]))) { - goto nomatch; - } - } - break; - nomatch: - ; - } - } - - return(ptr); -} - -/************************************************************************* -Accepts a specified string. Comparisons are case-insensitive. */ - -const char* -dict_accept( -/*========*/ - /* out: if string was accepted, the pointer - is moved after that, else ptr is returned */ - const char* ptr, /* in: scan from this */ - const char* string, /* in: accept only this string as the next - non-whitespace string */ - ibool* success)/* out: TRUE if accepted */ -{ - const char* old_ptr = ptr; - const char* old_ptr2; - - *success = FALSE; - - while (isspace(*ptr)) { - ptr++; - } - - old_ptr2 = ptr; - - ptr = dict_scan_to(ptr, string); - - if (*ptr == '\0' || old_ptr2 != ptr) { - return(old_ptr); - } - - *success = TRUE; - - return(ptr + ut_strlen(string)); -} - -/************************************************************************* -Scans an id. For the lexical definition of an 'id', see the code below. -Strips backquotes or double quotes from around the id. */ -static -const char* -dict_scan_id( -/*=========*/ - /* out: scanned to */ - const char* ptr, /* in: scanned to */ - mem_heap_t* heap, /* in: heap where to allocate the id - (NULL=id will not be allocated, but it - will point to string near ptr) */ - const char** id, /* out,own: the id; NULL if no id was - scannable */ - ibool accept_also_dot) - /* in: TRUE if also a dot can appear in a - non-quoted id; in a quoted id it can appear - always */ -{ - char quote = '\0'; - ulint len = 0; - const char* s; - char* d; - ulint id_len; - byte* b; - - *id = NULL; - - while (isspace(*ptr)) { - ptr++; - } - - if (*ptr == '\0') { - - return(ptr); - } - - if (*ptr == '`' || *ptr == '"') { - quote = *ptr++; - } - - s = ptr; - - if (quote) { - for (;;) { - if (!*ptr) { - /* Syntax error */ - return(ptr); - } - if (*ptr == quote) { - ptr++; - if (*ptr != quote) { - break; - } - } - ptr++; - len++; - } - } else { - while (!isspace(*ptr) && *ptr != '(' && *ptr != ')' - && (accept_also_dot || *ptr != '.') - && *ptr != ',' && *ptr != '\0') { - - ptr++; - } - - len = ptr - s; - } - - if (quote && heap) { - *id = d = mem_heap_alloc(heap, len + 1); - while (len--) { - if ((*d++ = *s++) == quote) { - s++; - } - } - *d++ = 0; - ut_a(*s == quote); - ut_a(s + 1 == ptr); - } else if (heap) { - *id = mem_heap_strdupl(heap, s, len); - } else { - /* no heap given: id will point to source string */ - *id = s; - } - - if (heap && !quote) { - /* EMS MySQL Manager sometimes adds characters 0xA0 (in - latin1, a 'non-breakable space') to the end of a table name. - But isspace(0xA0) is not true, which confuses our foreign key - parser. After the UTF-8 conversion in ha_innodb.cc, bytes 0xC2 - and 0xA0 are at the end of the string. - - TODO: we should lex the string using thd->charset_info, and - my_isspace(). Only after that, convert id names to UTF-8. */ - - b = (byte*)(*id); - id_len = strlen((char*) b); - - if (id_len >= 3 && b[id_len - 1] == 0xA0 - && b[id_len - 2] == 0xC2) { - - /* Strip the 2 last bytes */ - - b[id_len - 2] = '\0'; - } - } - - return(ptr); -} - -/************************************************************************* -Tries to scan a column name. */ -static -const char* -dict_scan_col( -/*==========*/ - /* out: scanned to */ - const char* ptr, /* in: scanned to */ - ibool* success,/* out: TRUE if success */ - dict_table_t* table, /* in: table in which the column is */ - dict_col_t** column, /* out: pointer to column if success */ - mem_heap_t* heap, /* in: heap where to allocate the name */ - const char** name) /* out,own: the column name; NULL if no name - was scannable */ -{ -#ifndef UNIV_HOTBACKUP - dict_col_t* col; - ulint i; - - *success = FALSE; - - ptr = dict_scan_id(ptr, heap, name, TRUE); - - if (*name == NULL) { - - return(ptr); /* Syntax error */ - } - - if (table == NULL) { - *success = TRUE; - *column = NULL; - } else { - for (i = 0; i < dict_table_get_n_cols(table); i++) { - - col = dict_table_get_nth_col(table, i); - - if (0 == innobase_strcasecmp(col->name, *name)) { - /* Found */ - - *success = TRUE; - *column = col; - strcpy((char*) *name, col->name); - - break; - } - } - } - - return(ptr); -#else /* UNIV_HOTBACKUP */ - /* This function depends on MySQL code that is not included in - InnoDB Hot Backup builds. Besides, this function should never - be called in InnoDB Hot Backup. */ - ut_error; -#endif /* UNIV_HOTBACKUP */ -} - -/************************************************************************* -Scans a table name from an SQL string. */ -static -const char* -dict_scan_table_name( -/*=================*/ - /* out: scanned to */ - const char* ptr, /* in: scanned to */ - dict_table_t** table, /* out: table object or NULL */ - const char* name, /* in: foreign key table name */ - ibool* success,/* out: TRUE if ok name found */ - mem_heap_t* heap, /* in: heap where to allocate the id */ - const char** ref_name)/* out,own: the table name; - NULL if no name was scannable */ -{ -#ifndef UNIV_HOTBACKUP - const char* database_name = NULL; - ulint database_name_len = 0; - const char* table_name = NULL; - ulint table_name_len; - const char* scan_name; - char* ref; - - *success = FALSE; - *table = NULL; - - ptr = dict_scan_id(ptr, heap, &scan_name, FALSE); - - if (scan_name == NULL) { - - return(ptr); /* Syntax error */ - } - - if (*ptr == '.') { - /* We scanned the database name; scan also the table name */ - - ptr++; - - database_name = scan_name; - database_name_len = strlen(database_name); - - ptr = dict_scan_id(ptr, heap, &table_name, FALSE); - - if (table_name == NULL) { - - return(ptr); /* Syntax error */ - } - } else { - /* To be able to read table dumps made with InnoDB-4.0.17 or - earlier, we must allow the dot separator between the database - name and the table name also to appear within a quoted - identifier! InnoDB used to print a constraint as: - ... REFERENCES `databasename.tablename` ... - starting from 4.0.18 it is - ... REFERENCES `databasename`.`tablename` ... */ - const char* s; - - for (s = scan_name; *s; s++) { - if (*s == '.') { - database_name = scan_name; - database_name_len = s - scan_name; - scan_name = ++s; - break;/* to do: multiple dots? */ - } - } - - table_name = scan_name; - } - - if (database_name == NULL) { - /* Use the database name of the foreign key table */ - - database_name = name; - database_name_len = dict_get_db_name_len(name); - } - - table_name_len = strlen(table_name); - - /* Copy database_name, '/', table_name, '\0' */ - ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2); - memcpy(ref, database_name, database_name_len); - ref[database_name_len] = '/'; - memcpy(ref + database_name_len + 1, table_name, table_name_len + 1); -#ifndef __WIN__ - if (srv_lower_case_table_names) { -#endif /* !__WIN__ */ - /* The table name is always put to lower case on Windows. */ - innobase_casedn_str(ref); -#ifndef __WIN__ - } -#endif /* !__WIN__ */ - - *success = TRUE; - *ref_name = ref; - *table = dict_table_get_low(ref); - - return(ptr); -#else /* UNIV_HOTBACKUP */ - /* This function depends on MySQL code that is not included in - InnoDB Hot Backup builds. Besides, this function should never - be called in InnoDB Hot Backup. */ - ut_error; -#endif /* UNIV_HOTBACKUP */ -} - -/************************************************************************* -Skips one id. The id is allowed to contain also '.'. */ -static -const char* -dict_skip_word( -/*===========*/ - /* out: scanned to */ - const char* ptr, /* in: scanned to */ - ibool* success)/* out: TRUE if success, FALSE if just spaces - left in string or a syntax error */ -{ - const char* start; - - *success = FALSE; - - ptr = dict_scan_id(ptr, NULL, &start, TRUE); - - if (start) { - *success = TRUE; - } - - return(ptr); -} - -/************************************************************************* -Removes MySQL comments from an SQL string. A comment is either -(a) '#' to the end of the line, -(b) '--<space>' to the end of the line, or -(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar -C comment syntax). */ -static -char* -dict_strip_comments( -/*================*/ - /* out, own: SQL string stripped from - comments; the caller must free this - with mem_free()! */ - const char* sql_string) /* in: SQL string */ -{ - char* str; - const char* sptr; - char* ptr; - /* unclosed quote character (0 if none) */ - char quote = 0; - - str = mem_alloc(strlen(sql_string) + 1); - - sptr = sql_string; - ptr = str; - - for (;;) { -scan_more: - if (*sptr == '\0') { - *ptr = '\0'; - - ut_a(ptr <= str + strlen(sql_string)); - - return(str); - } - - if (*sptr == quote) { - /* Closing quote character: do not look for - starting quote or comments. */ - quote = 0; - } else if (quote) { - /* Within quotes: do not look for - starting quotes or comments. */ - } else if (*sptr == '"' || *sptr == '`') { - /* Starting quote: remember the quote character. */ - quote = *sptr; - } else if (*sptr == '#' - || (sptr[0] == '-' && sptr[1] == '-' && - sptr[2] == ' ')) { - for (;;) { - /* In Unix a newline is 0x0A while in Windows - it is 0x0D followed by 0x0A */ - - if (*sptr == (char)0x0A - || *sptr == (char)0x0D - || *sptr == '\0') { - - goto scan_more; - } - - sptr++; - } - } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') { - for (;;) { - if (*sptr == '*' && *(sptr + 1) == '/') { - - sptr += 2; - - goto scan_more; - } - - if (*sptr == '\0') { - - goto scan_more; - } - - sptr++; - } - } - - *ptr = *sptr; - - ptr++; - sptr++; - } -} - -/************************************************************************* -Finds the highest <number> for foreign key constraints of the table. Looks -only at the >= 4.0.18-format id's, which are of the form -databasename/tablename_ibfk_<number>. */ -static -ulint -dict_table_get_highest_foreign_id( -/*==============================*/ - /* out: highest number, 0 if table has no new - format foreign key constraints */ - dict_table_t* table) /* in: table in the dictionary memory cache */ -{ - dict_foreign_t* foreign; - char* endp; - ulint biggest_id = 0; - ulint id; - ulint len; - - ut_a(table); - - len = ut_strlen(table->name); - foreign = UT_LIST_GET_FIRST(table->foreign_list); - - while (foreign) { - if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len - && 0 == ut_memcmp(foreign->id, table->name, len) - && 0 == ut_memcmp(foreign->id + len, - dict_ibfk, (sizeof dict_ibfk) - 1)) { - /* It is of the >= 4.0.18 format */ - - id = strtoul(foreign->id + len + ((sizeof dict_ibfk) - 1), - &endp, 10); - if (*endp == '\0') { - ut_a(id != biggest_id); - - if (id > biggest_id) { - biggest_id = id; - } - } - } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } - - return(biggest_id); -} - -/************************************************************************* -Reports a simple foreign key create clause syntax error. */ -static -void -dict_foreign_report_syntax_err( -/*===========================*/ - const char* name, /* in: table name */ - const char* start_of_latest_foreign, - /* in: start of the foreign key clause - in the SQL string */ - const char* ptr) /* in: place of the syntax error */ -{ - FILE* ef = dict_foreign_err_file; - - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nSyntax error close to:\n%s\n", - start_of_latest_foreign, ptr); - mutex_exit(&dict_foreign_err_mutex); -} - -/************************************************************************* -Scans a table create SQL string and adds to the data dictionary the foreign -key constraints declared in the string. This function should be called after -the indexes for a table have been created. Each foreign key constraint must -be accompanied with indexes in both participating tables. The indexes are -allowed to contain more fields than mentioned in the constraint. */ -static -ulint -dict_create_foreign_constraints_low( -/*================================*/ - /* out: error code or DB_SUCCESS */ - trx_t* trx, /* in: transaction */ - mem_heap_t* heap, /* in: memory heap */ - const char* sql_string, - /* in: CREATE TABLE or ALTER TABLE statement - where foreign keys are declared like: - FOREIGN KEY (a, b) REFERENCES table2(c, d), - table2 can be written also with the database - name before it: test.table2; the default - database is the database of parameter name */ - const char* name) /* in: table full name in the normalized form - database_name/table_name */ -{ - dict_table_t* table; - dict_table_t* referenced_table; - dict_table_t* table_to_alter; - ulint highest_id_so_far = 0; - dict_index_t* index; - dict_foreign_t* foreign; - const char* ptr = sql_string; - const char* start_of_latest_foreign = sql_string; - FILE* ef = dict_foreign_err_file; - const char* constraint_name; - ibool success; - ulint error; - const char* ptr1; - const char* ptr2; - ulint i; - ulint j; - ibool is_on_delete; - ulint n_on_deletes; - ulint n_on_updates; - dict_col_t* columns[500]; - const char* column_names[500]; - const char* referenced_table_name; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - table = dict_table_get_low(name); - - if (table == NULL) { - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, -"Cannot find the table in the internal data dictionary of InnoDB.\n" -"Create table statement:\n%s\n", sql_string); - mutex_exit(&dict_foreign_err_mutex); - - return(DB_ERROR); - } - - /* First check if we are actually doing an ALTER TABLE, and in that - case look for the table being altered */ - - ptr = dict_accept(ptr, "ALTER", &success); - - if (!success) { - - goto loop; - } - - ptr = dict_accept(ptr, "TABLE", &success); - - if (!success) { - - goto loop; - } - - /* We are doing an ALTER TABLE: scan the table name we are altering */ - - ptr = dict_scan_table_name(ptr, &table_to_alter, name, - &success, heap, &referenced_table_name); - if (!success) { - fprintf(stderr, -"InnoDB: Error: could not find the table being ALTERED in:\n%s\n", sql_string); - - return(DB_ERROR); - } - - /* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the - format databasename/tablename_ibfk_<number>, where <number> is local - to the table; look for the highest <number> for table_to_alter, so - that we can assign to new constraints higher numbers. */ - - /* If we are altering a temporary table, the table name after ALTER - TABLE does not correspond to the internal table name, and - table_to_alter is NULL. TODO: should we fix this somehow? */ - - if (table_to_alter == NULL) { - highest_id_so_far = 0; - } else { - highest_id_so_far = dict_table_get_highest_foreign_id( - table_to_alter); - } - - /* Scan for foreign key declarations in a loop */ -loop: - /* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */ - - ptr1 = dict_scan_to(ptr, "CONSTRAINT"); - ptr2 = dict_scan_to(ptr, "FOREIGN"); - - constraint_name = NULL; - - if (ptr1 < ptr2) { - /* The user may have specified a constraint name. Pick it so - that we can store 'databasename/constraintname' as the id of - of the constraint to system tables. */ - ptr = ptr1; - - ptr = dict_accept(ptr, "CONSTRAINT", &success); - - ut_a(success); - - if (!isspace(*ptr) && *ptr != '"' && *ptr != '`') { - goto loop; - } - - while (isspace(*ptr)) { - ptr++; - } - - /* read constraint name unless got "CONSTRAINT FOREIGN" */ - if (ptr != ptr2) { - ptr = dict_scan_id(ptr, heap, &constraint_name, FALSE); - } - } else { - ptr = ptr2; - } - - if (*ptr == '\0') { - /**********************************************************/ - /* The following call adds the foreign key constraints - to the data dictionary system tables on disk */ - - error = dict_create_add_foreigns_to_dictionary( - highest_id_so_far, table, trx); - return(error); - } - - start_of_latest_foreign = ptr; - - ptr = dict_accept(ptr, "FOREIGN", &success); - - if (!success) { - goto loop; - } - - if (!isspace(*ptr)) { - goto loop; - } - - ptr = dict_accept(ptr, "KEY", &success); - - if (!success) { - goto loop; - } - - ptr = dict_accept(ptr, "(", &success); - - if (!success) { - /* MySQL allows also an index id before the '('; we - skip it */ - ptr = dict_skip_word(ptr, &success); - - if (!success) { - dict_foreign_report_syntax_err(name, - start_of_latest_foreign, ptr); - - return(DB_CANNOT_ADD_CONSTRAINT); - } - - ptr = dict_accept(ptr, "(", &success); - - if (!success) { - /* We do not flag a syntax error here because in an - ALTER TABLE we may also have DROP FOREIGN KEY abc */ - - goto loop; - } - } - - i = 0; - - /* Scan the columns in the first list */ -col_loop1: - ut_a(i < (sizeof column_names) / sizeof *column_names); - ptr = dict_scan_col(ptr, &success, table, columns + i, - heap, column_names + i); - if (!success) { - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n", - start_of_latest_foreign, ptr); - mutex_exit(&dict_foreign_err_mutex); - - return(DB_CANNOT_ADD_CONSTRAINT); - } - - i++; - - ptr = dict_accept(ptr, ",", &success); - - if (success) { - goto col_loop1; - } - - ptr = dict_accept(ptr, ")", &success); - - if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); - return(DB_CANNOT_ADD_CONSTRAINT); - } - - /* Try to find an index which contains the columns - as the first fields and in the right order */ - - index = dict_foreign_find_index(table, column_names, i, NULL); - - if (!index) { - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fputs("There is no index in table ", ef); - ut_print_name(ef, NULL, name); - fprintf(ef, " where the columns appear\n" -"as the first columns. Constraint:\n%s\n" -"See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" -"for correct foreign key definition.\n", - start_of_latest_foreign); - mutex_exit(&dict_foreign_err_mutex); - - return(DB_CANNOT_ADD_CONSTRAINT); - } - ptr = dict_accept(ptr, "REFERENCES", &success); - - if (!success || !isspace(*ptr)) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); - return(DB_CANNOT_ADD_CONSTRAINT); - } - - /* Let us create a constraint struct */ - - foreign = dict_mem_foreign_create(); - - if (constraint_name) { - ulint db_len; - - /* Catenate 'databasename/' to the constraint name specified - by the user: we conceive the constraint as belonging to the - same MySQL 'database' as the table itself. We store the name - to foreign->id. */ - - db_len = dict_get_db_name_len(table->name); - - foreign->id = mem_heap_alloc(foreign->heap, - db_len + strlen(constraint_name) + 2); - - ut_memcpy(foreign->id, table->name, db_len); - foreign->id[db_len] = '/'; - strcpy(foreign->id + db_len + 1, constraint_name); - } - - foreign->foreign_table = table; - foreign->foreign_table_name = mem_heap_strdup(foreign->heap, - table->name); - foreign->foreign_index = index; - foreign->n_fields = i; - foreign->foreign_col_names = mem_heap_alloc(foreign->heap, - i * sizeof(void*)); - for (i = 0; i < foreign->n_fields; i++) { - foreign->foreign_col_names[i] = - mem_heap_strdup(foreign->heap, columns[i]->name); - } - - ptr = dict_scan_table_name(ptr, &referenced_table, name, - &success, heap, &referenced_table_name); - - /* Note that referenced_table can be NULL if the user has suppressed - checking of foreign key constraints! */ - - if (!success || (!referenced_table && trx->check_foreigns)) { - dict_foreign_free(foreign); - - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve table name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); - mutex_exit(&dict_foreign_err_mutex); - - return(DB_CANNOT_ADD_CONSTRAINT); - } - - ptr = dict_accept(ptr, "(", &success); - - if (!success) { - dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); - return(DB_CANNOT_ADD_CONSTRAINT); - } - - /* Scan the columns in the second list */ - i = 0; - -col_loop2: - ptr = dict_scan_col(ptr, &success, referenced_table, columns + i, - heap, column_names + i); - i++; - - if (!success) { - dict_foreign_free(foreign); - - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); - mutex_exit(&dict_foreign_err_mutex); - - return(DB_CANNOT_ADD_CONSTRAINT); - } - - ptr = dict_accept(ptr, ",", &success); - - if (success) { - goto col_loop2; - } - - ptr = dict_accept(ptr, ")", &success); - - if (!success || foreign->n_fields != i) { - dict_foreign_free(foreign); - - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); - return(DB_CANNOT_ADD_CONSTRAINT); - } - - n_on_deletes = 0; - n_on_updates = 0; - -scan_on_conditions: - /* Loop here as long as we can find ON ... conditions */ - - ptr = dict_accept(ptr, "ON", &success); - - if (!success) { - - goto try_find_index; - } - - ptr = dict_accept(ptr, "DELETE", &success); - - if (!success) { - ptr = dict_accept(ptr, "UPDATE", &success); - - if (!success) { - dict_foreign_free(foreign); - - dict_foreign_report_syntax_err(name, - start_of_latest_foreign, ptr); - return(DB_CANNOT_ADD_CONSTRAINT); - } - - is_on_delete = FALSE; - n_on_updates++; - } else { - is_on_delete = TRUE; - n_on_deletes++; - } - - ptr = dict_accept(ptr, "RESTRICT", &success); - - if (success) { - goto scan_on_conditions; - } - - ptr = dict_accept(ptr, "CASCADE", &success); - - if (success) { - if (is_on_delete) { - foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE; - } else { - foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE; - } - - goto scan_on_conditions; - } - - ptr = dict_accept(ptr, "NO", &success); - - if (success) { - ptr = dict_accept(ptr, "ACTION", &success); - - if (!success) { - dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, - start_of_latest_foreign, ptr); - - return(DB_CANNOT_ADD_CONSTRAINT); - } - - if (is_on_delete) { - foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION; - } else { - foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION; - } - - goto scan_on_conditions; - } - - ptr = dict_accept(ptr, "SET", &success); - - if (!success) { - dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); - return(DB_CANNOT_ADD_CONSTRAINT); - } - - ptr = dict_accept(ptr, "NULL", &success); - - if (!success) { - dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); - return(DB_CANNOT_ADD_CONSTRAINT); - } - - for (j = 0; j < foreign->n_fields; j++) { - if ((dict_index_get_nth_type( - foreign->foreign_index, j)->prtype) - & DATA_NOT_NULL) { - - /* It is not sensible to define SET NULL - if the column is not allowed to be NULL! */ - - dict_foreign_free(foreign); - - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have defined a SET NULL condition though some of the\n" - "columns are defined as NOT NULL.\n", start_of_latest_foreign); - mutex_exit(&dict_foreign_err_mutex); - - return(DB_CANNOT_ADD_CONSTRAINT); - } - } - - if (is_on_delete) { - foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL; - } else { - foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL; - } - - goto scan_on_conditions; - -try_find_index: - if (n_on_deletes > 1 || n_on_updates > 1) { - /* It is an error to define more than 1 action */ - - dict_foreign_free(foreign); - - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" -"You have twice an ON DELETE clause or twice an ON UPDATE clause.\n", - start_of_latest_foreign); - mutex_exit(&dict_foreign_err_mutex); - - return(DB_CANNOT_ADD_CONSTRAINT); - } - - /* Try to find an index which contains the columns as the first fields - and in the right order, and the types are the same as in - foreign->foreign_index */ - - if (referenced_table) { - index = dict_foreign_find_index(referenced_table, - column_names, i, - foreign->foreign_index); - if (!index) { - dict_foreign_free(foreign); - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" -"Cannot find an index in the referenced table where the\n" -"referenced columns appear as the first columns, or column types\n" -"in the table and the referenced table do not match for constraint.\n" -"See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" -"for correct foreign key definition.\n", - start_of_latest_foreign); - mutex_exit(&dict_foreign_err_mutex); - - return(DB_CANNOT_ADD_CONSTRAINT); - } - } else { - ut_a(trx->check_foreigns == FALSE); - index = NULL; - } - - foreign->referenced_index = index; - foreign->referenced_table = referenced_table; - - foreign->referenced_table_name = mem_heap_strdup(foreign->heap, - referenced_table_name); - - foreign->referenced_col_names = mem_heap_alloc(foreign->heap, - i * sizeof(void*)); - for (i = 0; i < foreign->n_fields; i++) { - foreign->referenced_col_names[i] - = mem_heap_strdup(foreign->heap, column_names[i]); - } - - /* We found an ok constraint definition: add to the lists */ - - UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign); - - if (referenced_table) { - UT_LIST_ADD_LAST(referenced_list, - referenced_table->referenced_list, - foreign); - } - - goto loop; -} - -/************************************************************************* -Scans a table create SQL string and adds to the data dictionary the foreign -key constraints declared in the string. This function should be called after -the indexes for a table have been created. Each foreign key constraint must -be accompanied with indexes in both participating tables. The indexes are -allowed to contain more fields than mentioned in the constraint. */ - -ulint -dict_create_foreign_constraints( -/*============================*/ - /* out: error code or DB_SUCCESS */ - trx_t* trx, /* in: transaction */ - const char* sql_string, /* in: table create statement where - foreign keys are declared like: - FOREIGN KEY (a, b) REFERENCES - table2(c, d), table2 can be written - also with the database - name before it: test.table2; the - default database id the database of - parameter name */ - const char* name) /* in: table full name in the - normalized form - database_name/table_name */ -{ - char* str; - ulint err; - mem_heap_t* heap; - - str = dict_strip_comments(sql_string); - heap = mem_heap_create(10000); - - err = dict_create_foreign_constraints_low(trx, heap, str, name); - - mem_heap_free(heap); - mem_free(str); - - return(err); -} - -/************************************************************************** -Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */ - -ulint -dict_foreign_parse_drop_constraints( -/*================================*/ - /* out: DB_SUCCESS or - DB_CANNOT_DROP_CONSTRAINT if - syntax error or the constraint - id does not match */ - mem_heap_t* heap, /* in: heap from which we can - allocate memory */ - trx_t* trx, /* in: transaction */ - dict_table_t* table, /* in: table */ - ulint* n, /* out: number of constraints - to drop */ - const char*** constraints_to_drop) /* out: id's of the - constraints to drop */ -{ - dict_foreign_t* foreign; - ibool success; - char* str; - const char* ptr; - const char* id; - FILE* ef = dict_foreign_err_file; - - *n = 0; - - *constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*)); - - str = dict_strip_comments(*(trx->mysql_query_str)); - ptr = str; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ -loop: - ptr = dict_scan_to(ptr, "DROP"); - - if (*ptr == '\0') { - mem_free(str); - - return(DB_SUCCESS); - } - - ptr = dict_accept(ptr, "DROP", &success); - - if (!isspace(*ptr)) { - - goto loop; - } - - ptr = dict_accept(ptr, "FOREIGN", &success); - - if (!success) { - - goto loop; - } - - ptr = dict_accept(ptr, "KEY", &success); - - if (!success) { - - goto syntax_error; - } - - ptr = dict_scan_id(ptr, heap, &id, TRUE); - - if (id == NULL) { - - goto syntax_error; - } - - ut_a(*n < 1000); - (*constraints_to_drop)[*n] = id; - (*n)++; - - /* Look for the given constraint id */ - - foreign = UT_LIST_GET_FIRST(table->foreign_list); - - while (foreign != NULL) { - if (0 == strcmp(foreign->id, id) - || (strchr(foreign->id, '/') - && 0 == strcmp(id, - dict_remove_db_name(foreign->id)))) { - /* Found */ - break; - } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } - - if (foreign == NULL) { - mutex_enter(&dict_foreign_err_mutex); - rewind(ef); - ut_print_timestamp(ef); - fputs( - " Error in dropping of a foreign key constraint of table ", ef); - ut_print_name(ef, NULL, table->name); - fputs(",\n" - "in SQL command\n", ef); - fputs(str, ef); - fputs("\nCannot find a constraint with the given id ", ef); - ut_print_name(ef, NULL, id); - fputs(".\n", ef); - mutex_exit(&dict_foreign_err_mutex); - - mem_free(str); - - return(DB_CANNOT_DROP_CONSTRAINT); - } - - goto loop; - -syntax_error: - mutex_enter(&dict_foreign_err_mutex); - rewind(ef); - ut_print_timestamp(ef); - fputs( - " Syntax error in dropping of a foreign key constraint of table ", ef); - ut_print_name(ef, NULL, table->name); - fprintf(ef, ",\n" - "close to:\n%s\n in SQL command\n%s\n", ptr, str); - mutex_exit(&dict_foreign_err_mutex); - - mem_free(str); - - return(DB_CANNOT_DROP_CONSTRAINT); -} - -/*==================== END OF FOREIGN KEY PROCESSING ====================*/ - -/************************************************************************** -Returns an index object if it is found in the dictionary cache. */ - -dict_index_t* -dict_index_get_if_in_cache( -/*=======================*/ - /* out: index, NULL if not found */ - dulint index_id) /* in: index id */ -{ - dict_table_t* table; - dict_index_t* index; - - if (dict_sys == NULL) { - return(NULL); - } - - mutex_enter(&(dict_sys->mutex)); - - table = UT_LIST_GET_FIRST(dict_sys->table_LRU); - - while (table) { - index = UT_LIST_GET_FIRST(table->indexes); - - while (index) { - if (0 == ut_dulint_cmp(index->id, index_id)) { - - goto found; - } - - index = UT_LIST_GET_NEXT(indexes, index); - } - - table = UT_LIST_GET_NEXT(table_LRU, table); - } - - index = NULL; -found: - mutex_exit(&(dict_sys->mutex)); - - return(index); -} - -/************************************************************************** -Creates an index tree struct. */ - -dict_tree_t* -dict_tree_create( -/*=============*/ - /* out, own: created tree */ - dict_index_t* index, /* in: the index for which to create: in the - case of a mixed tree, this should be the - index of the cluster object */ - ulint page_no)/* in: root page number of the index */ -{ - dict_tree_t* tree; - - tree = mem_alloc(sizeof(dict_tree_t)); - - /* Inherit info from the index */ - - tree->type = index->type; - tree->space = index->space; - tree->page = page_no; - - tree->id = index->id; - - UT_LIST_INIT(tree->tree_indexes); - - tree->magic_n = DICT_TREE_MAGIC_N; - - rw_lock_create(&(tree->lock)); - - rw_lock_set_level(&(tree->lock), SYNC_INDEX_TREE); - - return(tree); -} - -/************************************************************************** -Frees an index tree struct. */ - -void -dict_tree_free( -/*===========*/ - dict_tree_t* tree) /* in, own: index tree */ -{ - ut_a(tree); - ut_ad(tree->magic_n == DICT_TREE_MAGIC_N); - - rw_lock_free(&(tree->lock)); - mem_free(tree); -} - -/************************************************************************** -In an index tree, finds the index corresponding to a record in the tree. */ -UNIV_INLINE -dict_index_t* -dict_tree_find_index_low( -/*=====================*/ - /* out: index */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec) /* in: record for which to find correct - index */ -{ - dict_index_t* index; - dict_table_t* table; - dulint mix_id; - ulint len; - - index = UT_LIST_GET_FIRST(tree->tree_indexes); - ut_ad(index); - table = index->table; - - if ((index->type & DICT_CLUSTERED) - && (table->type != DICT_TABLE_ORDINARY)) { - - /* Get the mix id of the record */ - ut_a(!table->comp); - - mix_id = mach_dulint_read_compressed( - rec_get_nth_field_old(rec, table->mix_len, &len)); - - while (ut_dulint_cmp(table->mix_id, mix_id) != 0) { - - index = UT_LIST_GET_NEXT(tree_indexes, index); - table = index->table; - ut_ad(index); - } - } - - return(index); -} - -/************************************************************************** -In an index tree, finds the index corresponding to a record in the tree. */ - -dict_index_t* -dict_tree_find_index( -/*=================*/ - /* out: index */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec) /* in: record for which to find correct - index */ -{ - dict_index_t* index; - - index = dict_tree_find_index_low(tree, rec); - - return(index); -} - -/************************************************************************** -In an index tree, finds the index corresponding to a dtuple which is used -in a search to a tree. */ - -dict_index_t* -dict_tree_find_index_for_tuple( -/*===========================*/ - /* out: index; NULL if the tuple does not - contain the mix id field in a mixed tree */ - dict_tree_t* tree, /* in: index tree */ - dtuple_t* tuple) /* in: tuple for which to find index */ -{ - dict_index_t* index; - dict_table_t* table; - dulint mix_id; - - ut_ad(dtuple_check_typed(tuple)); - - if (UT_LIST_GET_LEN(tree->tree_indexes) == 1) { - - return(UT_LIST_GET_FIRST(tree->tree_indexes)); - } - - index = UT_LIST_GET_FIRST(tree->tree_indexes); - ut_ad(index); - table = index->table; - - if (dtuple_get_n_fields(tuple) <= table->mix_len) { - - return(NULL); - } - - /* Get the mix id of the record */ - - mix_id = mach_dulint_read_compressed( - dfield_get_data( - dtuple_get_nth_field(tuple, table->mix_len))); - - while (ut_dulint_cmp(table->mix_id, mix_id) != 0) { - - index = UT_LIST_GET_NEXT(tree_indexes, index); - table = index->table; - ut_ad(index); - } - - return(index); -} - -/*********************************************************************** -Checks if a table which is a mixed cluster member owns a record. */ - -ibool -dict_is_mixed_table_rec( -/*====================*/ - /* out: TRUE if the record belongs to this - table */ - dict_table_t* table, /* in: table in a mixed cluster */ - rec_t* rec) /* in: user record in the clustered index */ -{ - byte* mix_id_field; - ulint len; - - ut_ad(!table->comp); - - mix_id_field = rec_get_nth_field_old(rec, - table->mix_len, &len); - - return(len == table->mix_id_len - && !ut_memcmp(table->mix_id_buf, mix_id_field, len)); -} - -/************************************************************************** -Checks that a tuple has n_fields_cmp value in a sensible range, so that -no comparison can occur with the page number field in a node pointer. */ - -ibool -dict_tree_check_search_tuple( -/*=========================*/ - /* out: TRUE if ok */ - dict_tree_t* tree, /* in: index tree */ - dtuple_t* tuple) /* in: tuple used in a search */ -{ - dict_index_t* index; - - index = dict_tree_find_index_for_tuple(tree, tuple); - - if (index == NULL) { - - return(TRUE); - } - - ut_a(dtuple_get_n_fields_cmp(tuple) - <= dict_index_get_n_unique_in_tree(index)); - return(TRUE); -} - -/************************************************************************** -Builds a node pointer out of a physical record and a page number. */ - -dtuple_t* -dict_tree_build_node_ptr( -/*=====================*/ - /* out, own: node pointer */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec, /* in: record for which to build node - pointer */ - ulint page_no,/* in: page number to put in node pointer */ - mem_heap_t* heap, /* in: memory heap where pointer created */ - ulint level) /* in: level of rec in tree: 0 means leaf - level */ -{ - dtuple_t* tuple; - dict_index_t* ind; - dfield_t* field; - byte* buf; - ulint n_unique; - - ind = dict_tree_find_index_low(tree, rec); - - if (tree->type & DICT_UNIVERSAL) { - /* In a universal index tree, we take the whole record as - the node pointer if the reord is on the leaf level, - on non-leaf levels we remove the last field, which - contains the page number of the child page */ - - ut_a(!ind->table->comp); - n_unique = rec_get_n_fields_old(rec); - - if (level > 0) { - ut_a(n_unique > 1); - n_unique--; - } - } else { - n_unique = dict_index_get_n_unique_in_tree(ind); - } - - tuple = dtuple_create(heap, n_unique + 1); - - /* When searching in the tree for the node pointer, we must not do - comparison on the last field, the page number field, as on upper - levels in the tree there may be identical node pointers with a - different page number; therefore, we set the n_fields_cmp to one - less: */ - - dtuple_set_n_fields_cmp(tuple, n_unique); - - dict_index_copy_types(tuple, ind, n_unique); - - buf = mem_heap_alloc(heap, 4); - - mach_write_to_4(buf, page_no); - - field = dtuple_get_nth_field(tuple, n_unique); - dfield_set_data(field, buf, 4); - - dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4, 0); - - rec_copy_prefix_to_dtuple(tuple, rec, ind, n_unique, heap); - dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple) | - REC_STATUS_NODE_PTR); - - ut_ad(dtuple_check_typed(tuple)); - - return(tuple); -} - -/************************************************************************** -Copies an initial segment of a physical record, long enough to specify an -index entry uniquely. */ - -rec_t* -dict_tree_copy_rec_order_prefix( -/*============================*/ - /* out: pointer to the prefix record */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec, /* in: record for which to copy prefix */ - ulint* n_fields,/* out: number of fields copied */ - byte** buf, /* in/out: memory buffer for the copied prefix, - or NULL */ - ulint* buf_size)/* in/out: buffer size */ -{ - dict_index_t* index; - ulint n; - - index = dict_tree_find_index_low(tree, rec); - - if (tree->type & DICT_UNIVERSAL) { - ut_a(!index->table->comp); - n = rec_get_n_fields_old(rec); - } else { - n = dict_index_get_n_unique_in_tree(index); - } - - *n_fields = n; - return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size)); -} - -/************************************************************************** -Builds a typed data tuple out of a physical record. */ - -dtuple_t* -dict_tree_build_data_tuple( -/*=======================*/ - /* out, own: data tuple */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec, /* in: record for which to build data tuple */ - ulint n_fields,/* in: number of data fields */ - mem_heap_t* heap) /* in: memory heap where tuple created */ -{ - dtuple_t* tuple; - dict_index_t* ind; - - ind = dict_tree_find_index_low(tree, rec); - - ut_ad(ind->table->comp || n_fields <= rec_get_n_fields_old(rec)); - - tuple = dtuple_create(heap, n_fields); - - dict_index_copy_types(tuple, ind, n_fields); - - rec_copy_prefix_to_dtuple(tuple, rec, ind, n_fields, heap); - - ut_ad(dtuple_check_typed(tuple)); - - return(tuple); -} - -/************************************************************************* -Calculates the minimum record length in an index. */ - -ulint -dict_index_calc_min_rec_len( -/*========================*/ - dict_index_t* index) /* in: index */ -{ - ulint sum = 0; - ulint i; - - if (index->table->comp) { - ulint nullable = 0; - sum = REC_N_NEW_EXTRA_BYTES; - for (i = 0; i < dict_index_get_n_fields(index); i++) { - dtype_t*t = dict_index_get_nth_type(index, i); - ulint size = dtype_get_fixed_size(t); - sum += size; - if (!size) { - size = dtype_get_len(t); - sum += size < 128 ? 1 : 2; - } - if (!(dtype_get_prtype(t) & DATA_NOT_NULL)) - nullable++; - } - - /* round the NULL flags up to full bytes */ - sum += (nullable + 7) / 8; - - return(sum); - } - - for (i = 0; i < dict_index_get_n_fields(index); i++) { - sum += dtype_get_fixed_size(dict_index_get_nth_type(index, i)); - } - - if (sum > 127) { - sum += 2 * dict_index_get_n_fields(index); - } else { - sum += dict_index_get_n_fields(index); - } - - sum += REC_N_OLD_EXTRA_BYTES; - - return(sum); -} - -/************************************************************************* -Calculates new estimates for table and index statistics. The statistics -are used in query optimization. */ - -void -dict_update_statistics_low( -/*=======================*/ - dict_table_t* table, /* in: table */ - ibool has_dict_mutex __attribute__((unused))) - /* in: TRUE if the caller has the - dictionary mutex */ -{ - dict_index_t* index; - ulint size; - ulint sum_of_index_sizes = 0; - - if (table->ibd_file_missing) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: cannot calculate statistics for table %s\n" -"InnoDB: because the .ibd file is missing. For help, please refer to\n" -"InnoDB: " -"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n", - table->name); - - return; - } - - /* If we have set a high innodb_force_recovery level, do not calculate - statistics, as a badly corrupted index can cause a crash in it. */ - - if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { - - return; - } - - /* Find out the sizes of the indexes and how many different values - for the key they approximately have */ - - index = dict_table_get_first_index(table); - - if (index == NULL) { - /* Table definition is corrupt */ - - return; - } - - while (index) { - size = btr_get_size(index, BTR_TOTAL_SIZE); - - index->stat_index_size = size; - - sum_of_index_sizes += size; - - size = btr_get_size(index, BTR_N_LEAF_PAGES); - - if (size == 0) { - /* The root node of the tree is a leaf */ - size = 1; - } - - index->stat_n_leaf_pages = size; - - btr_estimate_number_of_different_key_vals(index); - - index = dict_table_get_next_index(index); - } - - index = dict_table_get_first_index(table); - - table->stat_n_rows = index->stat_n_diff_key_vals[ - dict_index_get_n_unique(index)]; - - table->stat_clustered_index_size = index->stat_index_size; - - table->stat_sum_of_other_index_sizes = sum_of_index_sizes - - index->stat_index_size; - - table->stat_initialized = TRUE; - - table->stat_modified_counter = 0; -} - -/************************************************************************* -Calculates new estimates for table and index statistics. The statistics -are used in query optimization. */ - -void -dict_update_statistics( -/*===================*/ - dict_table_t* table) /* in: table */ -{ - dict_update_statistics_low(table, FALSE); -} - -/************************************************************************** -Prints info of a foreign key constraint. */ -static -void -dict_foreign_print_low( -/*===================*/ - dict_foreign_t* foreign) /* in: foreign key constraint */ -{ - ulint i; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (", - foreign->id, foreign->foreign_table_name); - - for (i = 0; i < foreign->n_fields; i++) { - fprintf(stderr, " %s", foreign->foreign_col_names[i]); - } - - fprintf(stderr, " )\n" - " REFERENCES %s (", - foreign->referenced_table_name); - - for (i = 0; i < foreign->n_fields; i++) { - fprintf(stderr, " %s", foreign->referenced_col_names[i]); - } - - fputs(" )\n", stderr); -} - -/************************************************************************** -Prints a table data. */ - -void -dict_table_print( -/*=============*/ - dict_table_t* table) /* in: table */ -{ - mutex_enter(&(dict_sys->mutex)); - dict_table_print_low(table); - mutex_exit(&(dict_sys->mutex)); -} - -/************************************************************************** -Prints a table data when we know the table name. */ - -void -dict_table_print_by_name( -/*=====================*/ - const char* name) -{ - dict_table_t* table; - - mutex_enter(&(dict_sys->mutex)); - - table = dict_table_get_low(name); - - ut_a(table); - - dict_table_print_low(table); - mutex_exit(&(dict_sys->mutex)); -} - -/************************************************************************** -Prints a table data. */ - -void -dict_table_print_low( -/*=================*/ - dict_table_t* table) /* in: table */ -{ - dict_index_t* index; - dict_foreign_t* foreign; - ulint i; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - dict_update_statistics_low(table, TRUE); - - fprintf(stderr, -"--------------------------------------\n" -"TABLE: name %s, id %lu %lu, columns %lu, indexes %lu, appr.rows %lu\n" -" COLUMNS: ", - table->name, - (ulong) ut_dulint_get_high(table->id), - (ulong) ut_dulint_get_low(table->id), - (ulong) table->n_cols, - (ulong) UT_LIST_GET_LEN(table->indexes), - (ulong) table->stat_n_rows); - - for (i = 0; i < table->n_cols - 1; i++) { - dict_col_print_low(dict_table_get_nth_col(table, i)); - fputs("; ", stderr); - } - - putc('\n', stderr); - - index = UT_LIST_GET_FIRST(table->indexes); - - while (index != NULL) { - dict_index_print_low(index); - index = UT_LIST_GET_NEXT(indexes, index); - } - - foreign = UT_LIST_GET_FIRST(table->foreign_list); - - while (foreign != NULL) { - dict_foreign_print_low(foreign); - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } - - foreign = UT_LIST_GET_FIRST(table->referenced_list); - - while (foreign != NULL) { - dict_foreign_print_low(foreign); - foreign = UT_LIST_GET_NEXT(referenced_list, foreign); - } -} - -/************************************************************************** -Prints a column data. */ -static -void -dict_col_print_low( -/*===============*/ - dict_col_t* col) /* in: column */ -{ - dtype_t* type; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - type = dict_col_get_type(col); - fprintf(stderr, "%s: ", col->name); - - dtype_print(type); -} - -/************************************************************************** -Prints an index data. */ -static -void -dict_index_print_low( -/*=================*/ - dict_index_t* index) /* in: index */ -{ - dict_tree_t* tree; - ib_longlong n_vals; - ulint i; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - tree = index->tree; - - if (index->n_user_defined_cols > 0) { - n_vals = index->stat_n_diff_key_vals[ - index->n_user_defined_cols]; - } else { - n_vals = index->stat_n_diff_key_vals[1]; - } - - fprintf(stderr, - " INDEX: name %s, id %lu %lu, fields %lu/%lu, type %lu\n" - " root page %lu, appr.key vals %lu," - " leaf pages %lu, size pages %lu\n" - " FIELDS: ", - index->name, - (ulong) ut_dulint_get_high(tree->id), - (ulong) ut_dulint_get_low(tree->id), - (ulong) index->n_user_defined_cols, - (ulong) index->n_fields, (ulong) index->type, - (ulong) tree->page, - (ulong) n_vals, - (ulong) index->stat_n_leaf_pages, - (ulong) index->stat_index_size); - - for (i = 0; i < index->n_fields; i++) { - dict_field_print_low(dict_index_get_nth_field(index, i)); - } - - putc('\n', stderr); - -/* btr_print_size(tree); */ - -/* btr_print_tree(tree, 7); */ -} - -/************************************************************************** -Prints a field data. */ -static -void -dict_field_print_low( -/*=================*/ - dict_field_t* field) /* in: field */ -{ -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - fprintf(stderr, " %s", field->name); - - if (field->prefix_len != 0) { - fprintf(stderr, "(%lu)", (ulong) field->prefix_len); - } -} - -/************************************************************************** -Outputs info on a foreign key of a table in a format suitable for -CREATE TABLE. */ - -void -dict_print_info_on_foreign_key_in_create_format( -/*============================================*/ - FILE* file, /* in: file where to print */ - trx_t* trx, /* in: transaction */ - dict_foreign_t* foreign)/* in: foreign key constraint */ -{ - const char* stripped_id; - ulint i; - - if (strchr(foreign->id, '/')) { - /* Strip the preceding database name from the constraint id */ - stripped_id = foreign->id + 1 - + dict_get_db_name_len(foreign->id); - } else { - stripped_id = foreign->id; - } - - fputs(",\n CONSTRAINT ", file); - ut_print_name(file, trx, stripped_id); - fputs(" FOREIGN KEY (", file); - - for (i = 0;;) { - ut_print_name(file, trx, foreign->foreign_col_names[i]); - if (++i < foreign->n_fields) { - fputs(", ", file); - } else { - break; - } - } - - fputs(") REFERENCES ", file); - - if (dict_tables_have_same_db(foreign->foreign_table_name, - foreign->referenced_table_name)) { - /* Do not print the database name of the referenced table */ - ut_print_name(file, trx, dict_remove_db_name( - foreign->referenced_table_name)); - } else { - /* Look for the '/' in the table name */ - - i = 0; - while (foreign->referenced_table_name[i] != '/') { - i++; - } - - ut_print_namel(file, trx, foreign->referenced_table_name, i); - putc('.', file); - ut_print_name(file, trx, - foreign->referenced_table_name + i + 1); - } - - putc(' ', file); - putc('(', file); - - for (i = 0;;) { - ut_print_name(file, trx, foreign->referenced_col_names[i]); - if (++i < foreign->n_fields) { - fputs(", ", file); - } else { - break; - } - } - - putc(')', file); - - if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) { - fputs(" ON DELETE CASCADE", file); - } - - if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) { - fputs(" ON DELETE SET NULL", file); - } - - if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) { - fputs(" ON DELETE NO ACTION", file); - } - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) { - fputs(" ON UPDATE CASCADE", file); - } - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) { - fputs(" ON UPDATE SET NULL", file); - } - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) { - fputs(" ON UPDATE NO ACTION", file); - } -} - -/************************************************************************** -Outputs info on foreign keys of a table. */ - -void -dict_print_info_on_foreign_keys( -/*============================*/ - ibool create_table_format, /* in: if TRUE then print in - a format suitable to be inserted into - a CREATE TABLE, otherwise in the format - of SHOW TABLE STATUS */ - FILE* file, /* in: file where to print */ - trx_t* trx, /* in: transaction */ - dict_table_t* table) /* in: table */ -{ - dict_foreign_t* foreign; - - mutex_enter(&(dict_sys->mutex)); - - foreign = UT_LIST_GET_FIRST(table->foreign_list); - - if (foreign == NULL) { - mutex_exit(&(dict_sys->mutex)); - - return; - } - - while (foreign != NULL) { - if (create_table_format) { - dict_print_info_on_foreign_key_in_create_format( - file, trx, foreign); - } else { - ulint i; - fputs("; (", file); - - for (i = 0; i < foreign->n_fields; i++) { - if (i) { - putc(' ', file); - } - - ut_print_name(file, trx, - foreign->foreign_col_names[i]); - } - - fputs(") REFER ", file); - ut_print_name(file, trx, - foreign->referenced_table_name); - putc('(', file); - - for (i = 0; i < foreign->n_fields; i++) { - if (i) { - putc(' ', file); - } - ut_print_name(file, trx, - foreign->referenced_col_names[i]); - } - - putc(')', file); - - if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) { - fputs(" ON DELETE CASCADE", file); - } - - if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) { - fputs(" ON DELETE SET NULL", file); - } - - if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) { - fputs(" ON DELETE NO ACTION", file); - } - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) { - fputs(" ON UPDATE CASCADE", file); - } - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) { - fputs(" ON UPDATE SET NULL", file); - } - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) { - fputs(" ON UPDATE NO ACTION", file); - } - } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } - - mutex_exit(&(dict_sys->mutex)); -} - -/************************************************************************ -Displays the names of the index and the table. */ -void -dict_index_name_print( -/*==================*/ - FILE* file, /* in: output stream */ - trx_t* trx, /* in: transaction */ - const dict_index_t* index) /* in: index to print */ -{ - fputs("index ", file); - ut_print_name(file, trx, index->name); - fputs(" of table ", file); - ut_print_name(file, trx, index->table_name); -} diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c deleted file mode 100644 index 289b5dab4f2..00000000000 --- a/innobase/dict/dict0load.c +++ /dev/null @@ -1,1355 +0,0 @@ -/****************************************************** -Loads to the memory cache database object definitions -from dictionary tables - -(c) 1996 Innobase Oy - -Created 4/24/1996 Heikki Tuuri -*******************************************************/ - -#include "dict0load.h" -#ifndef UNIV_HOTBACKUP -#include "mysql_version.h" -#endif /* !UNIV_HOTBACKUP */ - -#ifdef UNIV_NONINL -#include "dict0load.ic" -#endif - -#include "btr0pcur.h" -#include "btr0btr.h" -#include "page0page.h" -#include "mach0data.h" -#include "dict0dict.h" -#include "dict0boot.h" -#include "rem0cmp.h" -#include "srv0start.h" -#include "srv0srv.h" - -/************************************************************************ -Finds the first table name in the given database. */ - -char* -dict_get_first_table_name_in_db( -/*============================*/ - /* out, own: table name, NULL if - does not exist; the caller must - free the memory in the string! */ - const char* name) /* in: database name which ends in '/' */ -{ - dict_table_t* sys_tables; - btr_pcur_t pcur; - dict_index_t* sys_index; - dtuple_t* tuple; - mem_heap_t* heap; - dfield_t* dfield; - rec_t* rec; - byte* field; - ulint len; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - heap = mem_heap_create(1000); - - mtr_start(&mtr); - - sys_tables = dict_table_get_low("SYS_TABLES"); - sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); - ut_a(!sys_tables->comp); - - tuple = dtuple_create(heap, 1); - dfield = dtuple_get_nth_field(tuple, 0); - - dfield_set_data(dfield, name, ut_strlen(name)); - dict_index_copy_types(tuple, sys_index, 1); - - btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); -loop: - rec = btr_pcur_get_rec(&pcur); - - if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { - /* Not found */ - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(NULL); - } - - field = rec_get_nth_field_old(rec, 0, &len); - - if (len < strlen(name) - || ut_memcmp(name, field, strlen(name)) != 0) { - /* Not found */ - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(NULL); - } - - if (!rec_get_deleted_flag(rec, sys_tables->comp)) { - - /* We found one */ - - char* table_name = mem_strdupl((char*) field, len); - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(table_name); - } - - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - - goto loop; -} - -/************************************************************************ -Prints to the standard output information on all tables found in the data -dictionary system table. */ - -void -dict_print(void) -/*============*/ -{ - dict_table_t* sys_tables; - dict_index_t* sys_index; - dict_table_t* table; - btr_pcur_t pcur; - rec_t* rec; - byte* field; - ulint len; - mtr_t mtr; - - /* Enlarge the fatal semaphore wait timeout during the InnoDB table - monitor printout */ - - mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ - mutex_exit(&kernel_mutex); - - mutex_enter(&(dict_sys->mutex)); - - mtr_start(&mtr); - - sys_tables = dict_table_get_low("SYS_TABLES"); - sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); - - btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur, - TRUE, &mtr); -loop: - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - - rec = btr_pcur_get_rec(&pcur); - - if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { - /* end of index */ - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - mutex_exit(&(dict_sys->mutex)); - - /* Restore the fatal semaphore wait timeout */ - - mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ - mutex_exit(&kernel_mutex); - - return; - } - - field = rec_get_nth_field_old(rec, 0, &len); - - if (!rec_get_deleted_flag(rec, sys_tables->comp)) { - - /* We found one */ - - char* table_name = mem_strdupl((char*) field, len); - - btr_pcur_store_position(&pcur, &mtr); - - mtr_commit(&mtr); - - table = dict_table_get_low(table_name); - mem_free(table_name); - - if (table == NULL) { - fputs("InnoDB: Failed to load table ", stderr); - ut_print_namel(stderr, NULL, (char*) field, len); - putc('\n', stderr); - } else { - /* The table definition was corrupt if there - is no index */ - - if (dict_table_get_first_index(table)) { - dict_update_statistics_low(table, TRUE); - } - - dict_table_print_low(table); - } - - mtr_start(&mtr); - - btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); - } - - goto loop; -} - -/************************************************************************ -In a crash recovery we already have all the tablespace objects created. -This function compares the space id information in the InnoDB data dictionary -to what we already read with fil_load_single_table_tablespaces(). - -In a normal startup, we create the tablespace objects for every table in -InnoDB's data dictionary, if the corresponding .ibd file exists. -We also scan the biggest space id, and store it to fil_system. */ - -void -dict_check_tablespaces_and_store_max_id( -/*====================================*/ - ibool in_crash_recovery) /* in: are we doing a crash recovery */ -{ - dict_table_t* sys_tables; - dict_index_t* sys_index; - btr_pcur_t pcur; - rec_t* rec; - byte* field; - ulint len; - ulint space_id; - ulint max_space_id = 0; - mtr_t mtr; - - mutex_enter(&(dict_sys->mutex)); - - mtr_start(&mtr); - - sys_tables = dict_table_get_low("SYS_TABLES"); - sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); - ut_a(!sys_tables->comp); - - btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur, - TRUE, &mtr); -loop: - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - - rec = btr_pcur_get_rec(&pcur); - - if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { - /* end of index */ - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - /* We must make the tablespace cache aware of the biggest - known space id */ - - /* printf("Biggest space id in data dictionary %lu\n", - max_space_id); */ - fil_set_max_space_id_if_bigger(max_space_id); - - mutex_exit(&(dict_sys->mutex)); - - return; - } - - field = rec_get_nth_field_old(rec, 0, &len); - - if (!rec_get_deleted_flag(rec, sys_tables->comp)) { - - /* We found one */ - - char* name = mem_strdupl((char*) field, len); - - field = rec_get_nth_field_old(rec, 9, &len); - ut_a(len == 4); - - space_id = mach_read_from_4(field); - - btr_pcur_store_position(&pcur, &mtr); - - mtr_commit(&mtr); - - if (space_id != 0 && in_crash_recovery) { - /* Check that the tablespace (the .ibd file) really - exists; print a warning to the .err log if not */ - - fil_space_for_table_exists_in_mem(space_id, name, - FALSE, TRUE, TRUE); - } - - if (space_id != 0 && !in_crash_recovery) { - /* It is a normal database startup: create the space - object and check that the .ibd file exists. */ - - fil_open_single_table_tablespace(FALSE, space_id, - name); - } - - mem_free(name); - - if (space_id > max_space_id) { - max_space_id = space_id; - } - - mtr_start(&mtr); - - btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); - } - - goto loop; -} - -/************************************************************************ -Loads definitions for table columns. */ -static -void -dict_load_columns( -/*==============*/ - dict_table_t* table, /* in: table */ - mem_heap_t* heap) /* in: memory heap for temporary storage */ -{ - dict_table_t* sys_columns; - dict_index_t* sys_index; - btr_pcur_t pcur; - dtuple_t* tuple; - dfield_t* dfield; - rec_t* rec; - byte* field; - ulint len; - byte* buf; - char* name; - ulint mtype; - ulint prtype; - ulint col_len; - ulint prec; - ulint i; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - mtr_start(&mtr); - - sys_columns = dict_table_get_low("SYS_COLUMNS"); - sys_index = UT_LIST_GET_FIRST(sys_columns->indexes); - ut_a(!sys_columns->comp); - - tuple = dtuple_create(heap, 1); - dfield = dtuple_get_nth_field(tuple, 0); - - buf = mem_heap_alloc(heap, 8); - mach_write_to_8(buf, table->id); - - dfield_set_data(dfield, buf, 8); - dict_index_copy_types(tuple, sys_index, 1); - - btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); - for (i = 0; i < table->n_cols - DATA_N_SYS_COLS; i++) { - - rec = btr_pcur_get_rec(&pcur); - - ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); - - ut_a(!rec_get_deleted_flag(rec, sys_columns->comp)); - - field = rec_get_nth_field_old(rec, 0, &len); - ut_ad(len == 8); - ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0); - - field = rec_get_nth_field_old(rec, 1, &len); - ut_ad(len == 4); - ut_a(i == mach_read_from_4(field)); - - ut_a(0 == ut_strcmp("NAME", - dict_field_get_col( - dict_index_get_nth_field(sys_index, 4))->name)); - - field = rec_get_nth_field_old(rec, 4, &len); - name = mem_heap_strdupl(heap, (char*) field, len); - - field = rec_get_nth_field_old(rec, 5, &len); - mtype = mach_read_from_4(field); - - field = rec_get_nth_field_old(rec, 6, &len); - prtype = mach_read_from_4(field); - - if (dtype_is_non_binary_string_type(mtype, prtype) - && dtype_get_charset_coll(prtype) == 0) { - /* This is a non-binary string type, and the table - was created with < 4.1.2. Use the default charset. */ - - prtype = dtype_form_prtype(prtype, - data_mysql_default_charset_coll); - } - - field = rec_get_nth_field_old(rec, 7, &len); - col_len = mach_read_from_4(field); - - ut_a(0 == ut_strcmp("PREC", - dict_field_get_col( - dict_index_get_nth_field(sys_index, 8))->name)); - - field = rec_get_nth_field_old(rec, 8, &len); - prec = mach_read_from_4(field); - - dict_mem_table_add_col(table, name, mtype, prtype, col_len, - prec); - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - } - - btr_pcur_close(&pcur); - mtr_commit(&mtr); -} - -/************************************************************************ -Report that an index field or index for a table has been delete marked. */ -static -void -dict_load_report_deleted_index( -/*===========================*/ - const char* name, /* in: table name */ - ulint field) /* in: index field, or ULINT_UNDEFINED */ -{ - fprintf(stderr, "InnoDB: Error: data dictionary entry" - " for table %s is corrupt!\n", name); - if (field != ULINT_UNDEFINED) { - fprintf(stderr, - "InnoDB: Index field %lu is delete marked.\n", field); - } else { - fputs("InnoDB: An index is delete marked.\n", stderr); - } -} - -/************************************************************************ -Loads definitions for index fields. */ -static -void -dict_load_fields( -/*=============*/ - dict_table_t* table, /* in: table */ - dict_index_t* index, /* in: index whose fields to load */ - mem_heap_t* heap) /* in: memory heap for temporary storage */ -{ - dict_table_t* sys_fields; - dict_index_t* sys_index; - btr_pcur_t pcur; - dtuple_t* tuple; - dfield_t* dfield; - ulint pos_and_prefix_len; - ulint prefix_len; - rec_t* rec; - byte* field; - ulint len; - byte* buf; - ulint i; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - UT_NOT_USED(table); - - mtr_start(&mtr); - - sys_fields = dict_table_get_low("SYS_FIELDS"); - sys_index = UT_LIST_GET_FIRST(sys_fields->indexes); - ut_a(!sys_fields->comp); - - tuple = dtuple_create(heap, 1); - dfield = dtuple_get_nth_field(tuple, 0); - - buf = mem_heap_alloc(heap, 8); - mach_write_to_8(buf, index->id); - - dfield_set_data(dfield, buf, 8); - dict_index_copy_types(tuple, sys_index, 1); - - btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); - for (i = 0; i < index->n_fields; i++) { - - rec = btr_pcur_get_rec(&pcur); - - ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); - if (rec_get_deleted_flag(rec, sys_fields->comp)) { - dict_load_report_deleted_index(table->name, i); - } - - field = rec_get_nth_field_old(rec, 0, &len); - ut_ad(len == 8); - ut_a(ut_memcmp(buf, field, len) == 0); - - field = rec_get_nth_field_old(rec, 1, &len); - ut_a(len == 4); - - /* The next field stores the field position in the index - and a possible column prefix length if the index field - does not contain the whole column. The storage format is - like this: if there is at least one prefix field in the index, - then the HIGH 2 bytes contain the field number (== i) and the - low 2 bytes the prefix length for the field. Otherwise the - field number (== i) is contained in the 2 LOW bytes. */ - - pos_and_prefix_len = mach_read_from_4(field); - - ut_a((pos_and_prefix_len & 0xFFFFUL) == i - || (pos_and_prefix_len & 0xFFFF0000UL) == (i << 16)); - - if ((i == 0 && pos_and_prefix_len > 0) - || (pos_and_prefix_len & 0xFFFF0000UL) > 0) { - - prefix_len = pos_and_prefix_len & 0xFFFFUL; - } else { - prefix_len = 0; - } - - ut_a(0 == ut_strcmp("COL_NAME", - dict_field_get_col( - dict_index_get_nth_field(sys_index, 4))->name)); - - field = rec_get_nth_field_old(rec, 4, &len); - - dict_mem_index_add_field(index, - mem_heap_strdupl(heap, (char*) field, len), 0, prefix_len); - - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - } - - btr_pcur_close(&pcur); - mtr_commit(&mtr); -} - -/************************************************************************ -Loads definitions for table indexes. Adds them to the data dictionary -cache. */ -static -ibool -dict_load_indexes( -/*==============*/ - /* out: TRUE if ok, FALSE if corruption - of dictionary table */ - dict_table_t* table, /* in: table */ - mem_heap_t* heap) /* in: memory heap for temporary storage */ -{ - dict_table_t* sys_indexes; - dict_index_t* sys_index; - dict_index_t* index; - btr_pcur_t pcur; - dtuple_t* tuple; - dfield_t* dfield; - rec_t* rec; - byte* field; - ulint len; - ulint name_len; - char* name_buf; - ulint type; - ulint space; - ulint page_no; - ulint n_fields; - byte* buf; - ibool is_sys_table; - dulint id; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - if ((ut_dulint_get_high(table->id) == 0) - && (ut_dulint_get_low(table->id) < DICT_HDR_FIRST_ID)) { - is_sys_table = TRUE; - } else { - is_sys_table = FALSE; - } - - mtr_start(&mtr); - - sys_indexes = dict_table_get_low("SYS_INDEXES"); - sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes); - ut_a(!sys_indexes->comp); - - tuple = dtuple_create(heap, 1); - dfield = dtuple_get_nth_field(tuple, 0); - - buf = mem_heap_alloc(heap, 8); - mach_write_to_8(buf, table->id); - - dfield_set_data(dfield, buf, 8); - dict_index_copy_types(tuple, sys_index, 1); - - btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); - for (;;) { - if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { - - break; - } - - rec = btr_pcur_get_rec(&pcur); - - field = rec_get_nth_field_old(rec, 0, &len); - ut_ad(len == 8); - - if (ut_memcmp(buf, field, len) != 0) { - break; - } - - if (rec_get_deleted_flag(rec, table->comp)) { - dict_load_report_deleted_index(table->name, - ULINT_UNDEFINED); - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(FALSE); - } - - field = rec_get_nth_field_old(rec, 1, &len); - ut_ad(len == 8); - id = mach_read_from_8(field); - - ut_a(0 == ut_strcmp("NAME", - dict_field_get_col( - dict_index_get_nth_field(sys_index, 4))->name)); - - field = rec_get_nth_field_old(rec, 4, &name_len); - name_buf = mem_heap_strdupl(heap, (char*) field, name_len); - - field = rec_get_nth_field_old(rec, 5, &len); - n_fields = mach_read_from_4(field); - - field = rec_get_nth_field_old(rec, 6, &len); - type = mach_read_from_4(field); - - field = rec_get_nth_field_old(rec, 7, &len); - space = mach_read_from_4(field); - - ut_a(0 == ut_strcmp("PAGE_NO", - dict_field_get_col( - dict_index_get_nth_field(sys_index, 8))->name)); - - field = rec_get_nth_field_old(rec, 8, &len); - page_no = mach_read_from_4(field); - - if (page_no == FIL_NULL) { - - fprintf(stderr, - "InnoDB: Error: trying to load index %s for table %s\n" - "InnoDB: but the index tree has been freed!\n", - name_buf, table->name); - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(FALSE); - } - - if ((type & DICT_CLUSTERED) == 0 - && NULL == dict_table_get_first_index(table)) { - - fprintf(stderr, - "InnoDB: Error: trying to load index %s for table %s\n" - "InnoDB: but the first index is not clustered!\n", - name_buf, table->name); - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(FALSE); - } - - if (is_sys_table - && ((type & DICT_CLUSTERED) - || ((table == dict_sys->sys_tables) - && (name_len == (sizeof "ID_IND") - 1) - && (0 == ut_memcmp(name_buf, "ID_IND", - name_len))))) { - - /* The index was created in memory already at booting - of the database server */ - } else { - index = dict_mem_index_create(table->name, name_buf, - space, type, n_fields); - index->id = id; - - dict_load_fields(table, index, heap); - dict_index_add_to_cache(table, index, page_no); - } - - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - } - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(TRUE); -} - -/************************************************************************ -Loads a table definition and also all its index definitions, and also -the cluster definition if the table is a member in a cluster. Also loads -all foreign key constraints where the foreign key is in the table or where -a foreign key references columns in this table. Adds all these to the data -dictionary cache. */ - -dict_table_t* -dict_load_table( -/*============*/ - /* out: table, NULL if does not exist; - if the table is stored in an .ibd file, - but the file does not exist, - then we set the ibd_file_missing flag TRUE - in the table object we return */ - const char* name) /* in: table name in the - databasename/tablename format */ -{ - ibool ibd_file_missing = FALSE; - dict_table_t* table; - dict_table_t* sys_tables; - btr_pcur_t pcur; - dict_index_t* sys_index; - dtuple_t* tuple; - mem_heap_t* heap; - dfield_t* dfield; - rec_t* rec; - byte* field; - ulint len; - ulint space; - ulint n_cols; - ulint err; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - heap = mem_heap_create(1000); - - mtr_start(&mtr); - - sys_tables = dict_table_get_low("SYS_TABLES"); - sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); - ut_a(!sys_tables->comp); - - tuple = dtuple_create(heap, 1); - dfield = dtuple_get_nth_field(tuple, 0); - - dfield_set_data(dfield, name, ut_strlen(name)); - dict_index_copy_types(tuple, sys_index, 1); - - btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); - rec = btr_pcur_get_rec(&pcur); - - if (!btr_pcur_is_on_user_rec(&pcur, &mtr) - || rec_get_deleted_flag(rec, sys_tables->comp)) { - /* Not found */ - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(NULL); - } - - field = rec_get_nth_field_old(rec, 0, &len); - - /* Check if the table name in record is the searched one */ - if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) { - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(NULL); - } - - ut_a(0 == ut_strcmp("SPACE", - dict_field_get_col( - dict_index_get_nth_field(sys_index, 9))->name)); - - field = rec_get_nth_field_old(rec, 9, &len); - space = mach_read_from_4(field); - - /* Check if the tablespace exists and has the right name */ - if (space != 0) { - if (fil_space_for_table_exists_in_mem(space, name, FALSE, - FALSE, FALSE)) { - /* Ok; (if we did a crash recovery then the tablespace - can already be in the memory cache) */ - } else { - /* In >= 4.1.9, InnoDB scans the data dictionary also - at a normal mysqld startup. It is an error if the - space object does not exist in memory. */ - - ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: error: space object of table %s,\n" -"InnoDB: space id %lu did not exist in memory. Retrying an open.\n", - name, (ulong)space); - /* Try to open the tablespace */ - if (!fil_open_single_table_tablespace(TRUE, - space, name)) { - /* We failed to find a sensible tablespace - file */ - - ibd_file_missing = TRUE; - } - } - } - - ut_a(0 == ut_strcmp("N_COLS", - dict_field_get_col( - dict_index_get_nth_field(sys_index, 4))->name)); - - field = rec_get_nth_field_old(rec, 4, &len); - n_cols = mach_read_from_4(field); - - /* The high-order bit of N_COLS is the "compact format" flag. */ - table = dict_mem_table_create(name, space, - n_cols & ~0x80000000UL, - !!(n_cols & 0x80000000UL)); - - table->ibd_file_missing = ibd_file_missing; - - ut_a(0 == ut_strcmp("ID", - dict_field_get_col( - dict_index_get_nth_field(sys_index, 3))->name)); - - field = rec_get_nth_field_old(rec, 3, &len); - table->id = mach_read_from_8(field); - - field = rec_get_nth_field_old(rec, 5, &len); - table->type = mach_read_from_4(field); - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - ut_error; -#if 0 /* clustered tables have not been implemented yet */ - field = rec_get_nth_field_old(rec, 6, &len); - table->mix_id = mach_read_from_8(field); - - field = rec_get_nth_field_old(rec, 8, &len); - table->cluster_name = mem_heap_strdupl(heap, (char*) field, len); -#endif - } - - if ((table->type == DICT_TABLE_CLUSTER) - || (table->type == DICT_TABLE_CLUSTER_MEMBER)) { - - field = rec_get_nth_field_old(rec, 7, &len); - ut_a(len == 4); - table->mix_len = mach_read_from_4(field); - } - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - /* Load the cluster table definition if not yet in - memory cache */ - dict_table_get_low(table->cluster_name); - } - - dict_load_columns(table, heap); - - dict_table_add_to_cache(table); - - dict_load_indexes(table, heap); - - err = dict_load_foreigns(table->name); -/* - if (err != DB_SUCCESS) { - - mutex_enter(&dict_foreign_err_mutex); - - ut_print_timestamp(stderr); - - fprintf(stderr, -" InnoDB: Error: could not make a foreign key definition to match\n" -"InnoDB: the foreign key table or the referenced table!\n" -"InnoDB: The data dictionary of InnoDB is corrupt. You may need to drop\n" -"InnoDB: and recreate the foreign key table or the referenced table.\n" -"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n" -"InnoDB: Latest foreign key error printout:\n%s\n", dict_foreign_err_buf); - - mutex_exit(&dict_foreign_err_mutex); - } -*/ - mem_heap_free(heap); - - return(table); -} - -/*************************************************************************** -Loads a table object based on the table id. */ - -dict_table_t* -dict_load_table_on_id( -/*==================*/ - /* out: table; NULL if table does not exist */ - dulint table_id) /* in: table id */ -{ - byte id_buf[8]; - btr_pcur_t pcur; - mem_heap_t* heap; - dtuple_t* tuple; - dfield_t* dfield; - dict_index_t* sys_table_ids; - dict_table_t* sys_tables; - rec_t* rec; - byte* field; - ulint len; - dict_table_t* table; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - /* NOTE that the operation of this function is protected by - the dictionary mutex, and therefore no deadlocks can occur - with other dictionary operations. */ - - mtr_start(&mtr); - /*---------------------------------------------------*/ - /* Get the secondary index based on ID for table SYS_TABLES */ - sys_tables = dict_sys->sys_tables; - sys_table_ids = dict_table_get_next_index( - dict_table_get_first_index(sys_tables)); - ut_a(!sys_tables->comp); - heap = mem_heap_create(256); - - tuple = dtuple_create(heap, 1); - dfield = dtuple_get_nth_field(tuple, 0); - - /* Write the table id in byte format to id_buf */ - mach_write_to_8(id_buf, table_id); - - dfield_set_data(dfield, id_buf, 8); - dict_index_copy_types(tuple, sys_table_ids, 1); - - btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); - rec = btr_pcur_get_rec(&pcur); - - if (!btr_pcur_is_on_user_rec(&pcur, &mtr) - || rec_get_deleted_flag(rec, sys_tables->comp)) { - /* Not found */ - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(NULL); - } - - /*---------------------------------------------------*/ - /* Now we have the record in the secondary index containing the - table ID and NAME */ - - rec = btr_pcur_get_rec(&pcur); - field = rec_get_nth_field_old(rec, 0, &len); - ut_ad(len == 8); - - /* Check if the table id in record is the one searched for */ - if (ut_dulint_cmp(table_id, mach_read_from_8(field)) != 0) { - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(NULL); - } - - /* Now we get the table name from the record */ - field = rec_get_nth_field_old(rec, 1, &len); - /* Load the table definition to memory */ - table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len)); - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(table); -} - -/************************************************************************ -This function is called when the database is booted. Loads system table -index definitions except for the clustered index which is added to the -dictionary cache at booting before calling this function. */ - -void -dict_load_sys_table( -/*================*/ - dict_table_t* table) /* in: system table */ -{ - mem_heap_t* heap; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - heap = mem_heap_create(1000); - - dict_load_indexes(table, heap); - - mem_heap_free(heap); -} - -/************************************************************************ -Loads foreign key constraint col names (also for the referenced table). */ -static -void -dict_load_foreign_cols( -/*===================*/ - const char* id, /* in: foreign constraint id as a null- - terminated string */ - dict_foreign_t* foreign)/* in: foreign constraint object */ -{ - dict_table_t* sys_foreign_cols; - dict_index_t* sys_index; - btr_pcur_t pcur; - dtuple_t* tuple; - dfield_t* dfield; - rec_t* rec; - byte* field; - ulint len; - ulint i; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - foreign->foreign_col_names = mem_heap_alloc(foreign->heap, - foreign->n_fields * sizeof(void*)); - - foreign->referenced_col_names = mem_heap_alloc(foreign->heap, - foreign->n_fields * sizeof(void*)); - mtr_start(&mtr); - - sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS"); - sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes); - ut_a(!sys_foreign_cols->comp); - - tuple = dtuple_create(foreign->heap, 1); - dfield = dtuple_get_nth_field(tuple, 0); - - dfield_set_data(dfield, id, ut_strlen(id)); - dict_index_copy_types(tuple, sys_index, 1); - - btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); - for (i = 0; i < foreign->n_fields; i++) { - - rec = btr_pcur_get_rec(&pcur); - - ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); - ut_a(!rec_get_deleted_flag(rec, sys_foreign_cols->comp)); - - field = rec_get_nth_field_old(rec, 0, &len); - ut_a(len == ut_strlen(id)); - ut_a(ut_memcmp(id, field, len) == 0); - - field = rec_get_nth_field_old(rec, 1, &len); - ut_a(len == 4); - ut_a(i == mach_read_from_4(field)); - - field = rec_get_nth_field_old(rec, 4, &len); - foreign->foreign_col_names[i] = - mem_heap_strdupl(foreign->heap, (char*) field, len); - - field = rec_get_nth_field_old(rec, 5, &len); - foreign->referenced_col_names[i] = - mem_heap_strdupl(foreign->heap, (char*) field, len); - - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - } - - btr_pcur_close(&pcur); - mtr_commit(&mtr); -} - -/*************************************************************************** -Loads a foreign key constraint to the dictionary cache. */ -static -ulint -dict_load_foreign( -/*==============*/ - /* out: DB_SUCCESS or error code */ - const char* id) /* in: foreign constraint id as a - null-terminated string */ -{ - dict_foreign_t* foreign; - dict_table_t* sys_foreign; - btr_pcur_t pcur; - dict_index_t* sys_index; - dtuple_t* tuple; - mem_heap_t* heap2; - dfield_t* dfield; - rec_t* rec; - byte* field; - ulint len; - ulint err; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - heap2 = mem_heap_create(1000); - - mtr_start(&mtr); - - sys_foreign = dict_table_get_low("SYS_FOREIGN"); - sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes); - ut_a(!sys_foreign->comp); - - tuple = dtuple_create(heap2, 1); - dfield = dtuple_get_nth_field(tuple, 0); - - dfield_set_data(dfield, id, ut_strlen(id)); - dict_index_copy_types(tuple, sys_index, 1); - - btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); - rec = btr_pcur_get_rec(&pcur); - - if (!btr_pcur_is_on_user_rec(&pcur, &mtr) - || rec_get_deleted_flag(rec, sys_foreign->comp)) { - /* Not found */ - - fprintf(stderr, - "InnoDB: Error A: cannot load foreign constraint %s\n", - id); - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap2); - - return(DB_ERROR); - } - - field = rec_get_nth_field_old(rec, 0, &len); - - /* Check if the id in record is the searched one */ - if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) { - - fprintf(stderr, - "InnoDB: Error B: cannot load foreign constraint %s\n", - id); - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap2); - - return(DB_ERROR); - } - - /* Read the table names and the number of columns associated - with the constraint */ - - mem_heap_free(heap2); - - foreign = dict_mem_foreign_create(); - - foreign->n_fields = - mach_read_from_4(rec_get_nth_field_old(rec, 5, &len)); - - ut_a(len == 4); - - /* We store the type to the bits 24-31 of n_fields */ - - foreign->type = foreign->n_fields >> 24; - foreign->n_fields = foreign->n_fields & 0xFFFFFFUL; - - foreign->id = mem_heap_strdup(foreign->heap, id); - - field = rec_get_nth_field_old(rec, 3, &len); - foreign->foreign_table_name = - mem_heap_strdupl(foreign->heap, (char*) field, len); - - field = rec_get_nth_field_old(rec, 4, &len); - foreign->referenced_table_name = - mem_heap_strdupl(foreign->heap, (char*) field, len); - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - dict_load_foreign_cols(id, foreign); - - /* If the foreign table is not yet in the dictionary cache, we - have to load it so that we are able to make type comparisons - in the next function call. */ - - dict_table_get_low(foreign->foreign_table_name); - - /* Note that there may already be a foreign constraint object in - the dictionary cache for this constraint: then the following - call only sets the pointers in it to point to the appropriate table - and index objects and frees the newly created object foreign. - Adding to the cache should always succeed since we are not creating - a new foreign key constraint but loading one from the data - dictionary. */ - - err = dict_foreign_add_to_cache(foreign); - - return(err); -} - -/*************************************************************************** -Loads foreign key constraints where the table is either the foreign key -holder or where the table is referenced by a foreign key. Adds these -constraints to the data dictionary. Note that we know that the dictionary -cache already contains all constraints where the other relevant table is -already in the dictionary cache. */ - -ulint -dict_load_foreigns( -/*===============*/ - /* out: DB_SUCCESS or error code */ - const char* table_name) /* in: table name */ -{ - btr_pcur_t pcur; - mem_heap_t* heap; - dtuple_t* tuple; - dfield_t* dfield; - dict_index_t* sec_index; - dict_table_t* sys_foreign; - rec_t* rec; - byte* field; - ulint len; - char* id ; - ulint err; - mtr_t mtr; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - sys_foreign = dict_table_get_low("SYS_FOREIGN"); - - if (sys_foreign == NULL) { - /* No foreign keys defined yet in this database */ - - fprintf(stderr, - "InnoDB: Error: no foreign key system tables in the database\n"); - - return(DB_ERROR); - } - - ut_a(!sys_foreign->comp); - mtr_start(&mtr); - - /* Get the secondary index based on FOR_NAME from table - SYS_FOREIGN */ - - sec_index = dict_table_get_next_index( - dict_table_get_first_index(sys_foreign)); -start_load: - heap = mem_heap_create(256); - - tuple = dtuple_create(heap, 1); - dfield = dtuple_get_nth_field(tuple, 0); - - dfield_set_data(dfield, table_name, ut_strlen(table_name)); - dict_index_copy_types(tuple, sec_index, 1); - - btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE, - BTR_SEARCH_LEAF, &pcur, &mtr); -loop: - rec = btr_pcur_get_rec(&pcur); - - if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { - /* End of index */ - - goto load_next_index; - } - - /* Now we have the record in the secondary index containing a table - name and a foreign constraint ID */ - - rec = btr_pcur_get_rec(&pcur); - field = rec_get_nth_field_old(rec, 0, &len); - - /* Check if the table name in the record is the one searched for; the - following call does the comparison in the latin1_swedish_ci - charset-collation, in a case-insensitive way. */ - - if (0 != cmp_data_data(dfield_get_type(dfield), - dfield_get_data(dfield), dfield_get_len(dfield), - field, len)) { - - goto load_next_index; - } - - /* Since table names in SYS_FOREIGN are stored in a case-insensitive - order, we have to check that the table name matches also in a binary - string comparison. On Unix, MySQL allows table names that only differ - in character case. */ - - if (0 != ut_memcmp(field, table_name, len)) { - - goto next_rec; - } - - if (rec_get_deleted_flag(rec, sys_foreign->comp)) { - - goto next_rec; - } - - /* Now we get a foreign key constraint id */ - field = rec_get_nth_field_old(rec, 1, &len); - id = mem_heap_strdupl(heap, (char*) field, len); - - btr_pcur_store_position(&pcur, &mtr); - - mtr_commit(&mtr); - - /* Load the foreign constraint definition to the dictionary cache */ - - err = dict_load_foreign(id); - - if (err != DB_SUCCESS) { - btr_pcur_close(&pcur); - mem_heap_free(heap); - - return(err); - } - - mtr_start(&mtr); - - btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); -next_rec: - btr_pcur_move_to_next_user_rec(&pcur, &mtr); - - goto loop; - -load_next_index: - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - sec_index = dict_table_get_next_index(sec_index); - - if (sec_index != NULL) { - - mtr_start(&mtr); - - goto start_load; - } - - return(DB_SUCCESS); -} diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c deleted file mode 100644 index 48b9f28d292..00000000000 --- a/innobase/dict/dict0mem.c +++ /dev/null @@ -1,293 +0,0 @@ -/********************************************************************** -Data dictionary memory object creation - -(c) 1996 Innobase Oy - -Created 1/8/1996 Heikki Tuuri -***********************************************************************/ - -#include "dict0mem.h" - -#ifdef UNIV_NONINL -#include "dict0mem.ic" -#endif - -#include "rem0rec.h" -#include "data0type.h" -#include "mach0data.h" -#include "dict0dict.h" -#include "que0que.h" -#include "pars0pars.h" -#include "lock0lock.h" - -#define DICT_HEAP_SIZE 100 /* initial memory heap size when - creating a table or index object */ - -/************************************************************************** -Creates a table memory object. */ - -dict_table_t* -dict_mem_table_create( -/*==================*/ - /* out, own: table object */ - const char* name, /* in: table name */ - ulint space, /* in: space where the clustered index of - the table is placed; this parameter is - ignored if the table is made a member of - a cluster */ - ulint n_cols, /* in: number of columns */ - ibool comp) /* in: TRUE=compact page format */ -{ - dict_table_t* table; - mem_heap_t* heap; - - ut_ad(name); - - heap = mem_heap_create(DICT_HEAP_SIZE); - - table = mem_heap_alloc(heap, sizeof(dict_table_t)); - - table->heap = heap; - - table->type = DICT_TABLE_ORDINARY; - table->name = mem_heap_strdup(heap, name); - table->dir_path_of_temp_table = NULL; - table->space = space; - table->ibd_file_missing = FALSE; - table->tablespace_discarded = FALSE; - table->comp = comp; - table->n_def = 0; - table->n_cols = n_cols + DATA_N_SYS_COLS; - table->mem_fix = 0; - - table->n_mysql_handles_opened = 0; - table->n_foreign_key_checks_running = 0; - - table->cached = FALSE; - - table->mix_id = ut_dulint_zero; - table->mix_len = 0; - - table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS) - * sizeof(dict_col_t)); - UT_LIST_INIT(table->indexes); - - table->auto_inc_lock = mem_heap_alloc(heap, lock_get_size()); - - table->query_cache_inv_trx_id = ut_dulint_zero; - - UT_LIST_INIT(table->locks); - UT_LIST_INIT(table->foreign_list); - UT_LIST_INIT(table->referenced_list); - - table->does_not_fit_in_memory = FALSE; - - table->stat_initialized = FALSE; - - table->stat_modified_counter = 0; - - mutex_create(&(table->autoinc_mutex)); - mutex_set_level(&(table->autoinc_mutex), SYNC_DICT_AUTOINC_MUTEX); - - table->autoinc_inited = FALSE; - - table->magic_n = DICT_TABLE_MAGIC_N; - - return(table); -} - -/************************************************************************** -Creates a cluster memory object. */ - -dict_table_t* -dict_mem_cluster_create( -/*====================*/ - /* out, own: cluster object */ - const char* name, /* in: cluster name */ - ulint space, /* in: space where the clustered indexes - of the member tables are placed */ - ulint n_cols, /* in: number of columns */ - ulint mix_len)/* in: length of the common key prefix in the - cluster */ -{ - dict_table_t* cluster; - - /* Clustered tables cannot work with the compact record format. */ - cluster = dict_mem_table_create(name, space, n_cols, FALSE); - - cluster->type = DICT_TABLE_CLUSTER; - cluster->mix_len = mix_len; - - return(cluster); -} - -/************************************************************************** -Declares a non-published table as a member in a cluster. */ - -void -dict_mem_table_make_cluster_member( -/*===============================*/ - dict_table_t* table, /* in: non-published table */ - const char* cluster_name) /* in: cluster name */ -{ - table->type = DICT_TABLE_CLUSTER_MEMBER; - table->cluster_name = cluster_name; -} - -/************************************************************************** -Adds a column definition to a table. */ - -void -dict_mem_table_add_col( -/*===================*/ - dict_table_t* table, /* in: table */ - const char* name, /* in: column name */ - ulint mtype, /* in: main datatype */ - ulint prtype, /* in: precise type */ - ulint len, /* in: length */ - ulint prec) /* in: precision */ -{ - dict_col_t* col; - dtype_t* type; - - ut_ad(table && name); - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - table->n_def++; - - col = dict_table_get_nth_col(table, table->n_def - 1); - - col->ind = table->n_def - 1; - col->name = mem_heap_strdup(table->heap, name); - col->table = table; - col->ord_part = 0; - - col->clust_pos = ULINT_UNDEFINED; - - type = dict_col_get_type(col); - - dtype_set(type, mtype, prtype, len, prec); -} - -/************************************************************************** -Creates an index memory object. */ - -dict_index_t* -dict_mem_index_create( -/*==================*/ - /* out, own: index object */ - const char* table_name, /* in: table name */ - const char* index_name, /* in: index name */ - ulint space, /* in: space where the index tree is - placed, ignored if the index is of - the clustered type */ - ulint type, /* in: DICT_UNIQUE, - DICT_CLUSTERED, ... ORed */ - ulint n_fields) /* in: number of fields */ -{ - dict_index_t* index; - mem_heap_t* heap; - - ut_ad(table_name && index_name); - - heap = mem_heap_create(DICT_HEAP_SIZE); - index = mem_heap_alloc(heap, sizeof(dict_index_t)); - - index->heap = heap; - - index->type = type; - index->space = space; - index->name = mem_heap_strdup(heap, index_name); - index->table_name = table_name; - index->table = NULL; - index->n_def = index->n_nullable = 0; - index->n_fields = n_fields; - index->fields = mem_heap_alloc(heap, 1 + n_fields - * sizeof(dict_field_t)); - /* The '1 +' above prevents allocation - of an empty mem block */ - index->stat_n_diff_key_vals = NULL; - - index->cached = FALSE; - index->magic_n = DICT_INDEX_MAGIC_N; - - return(index); -} - -/************************************************************************** -Creates and initializes a foreign constraint memory object. */ - -dict_foreign_t* -dict_mem_foreign_create(void) -/*=========================*/ - /* out, own: foreign constraint struct */ -{ - dict_foreign_t* foreign; - mem_heap_t* heap; - - heap = mem_heap_create(100); - - foreign = mem_heap_alloc(heap, sizeof(dict_foreign_t)); - - foreign->heap = heap; - - foreign->id = NULL; - - foreign->type = 0; - foreign->foreign_table_name = NULL; - foreign->foreign_table = NULL; - foreign->foreign_col_names = NULL; - - foreign->referenced_table_name = NULL; - foreign->referenced_table = NULL; - foreign->referenced_col_names = NULL; - - foreign->n_fields = 0; - - foreign->foreign_index = NULL; - foreign->referenced_index = NULL; - - return(foreign); -} - -/************************************************************************** -Adds a field definition to an index. NOTE: does not take a copy -of the column name if the field is a column. The memory occupied -by the column name may be released only after publishing the index. */ - -void -dict_mem_index_add_field( -/*=====================*/ - dict_index_t* index, /* in: index */ - const char* name, /* in: column name */ - ulint order, /* in: order criterion; 0 means an - ascending order */ - ulint prefix_len) /* in: 0 or the column prefix length - in a MySQL index like - INDEX (textcol(25)) */ -{ - dict_field_t* field; - - ut_ad(index && name); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - - index->n_def++; - - field = dict_index_get_nth_field(index, index->n_def - 1); - - field->name = name; - field->order = order; - - field->prefix_len = prefix_len; -} - -/************************************************************************** -Frees an index memory object. */ - -void -dict_mem_index_free( -/*================*/ - dict_index_t* index) /* in: index */ -{ - mem_heap_free(index->heap); -} diff --git a/innobase/dict/makefilewin b/innobase/dict/makefilewin deleted file mode 100644 index e828d06943c..00000000000 --- a/innobase/dict/makefilewin +++ /dev/null @@ -1,21 +0,0 @@ -include ..\include\makefile.i - -dict.lib: dict0dict.obj dict0boot.obj dict0load.obj dict0mem.obj dict0crea.obj - lib -out:..\libs\dict.lib dict0dict.obj dict0boot.obj dict0load.obj dict0mem.obj dict0crea.obj - -dict0dict.obj: dict0dict.c - $(CCOM) $(CFL) -c dict0dict.c - -dict0boot.obj: dict0boot.c - $(CCOM) $(CFL) -c dict0boot.c - -dict0mem.obj: dict0mem.c - $(CCOM) $(CFL) -c dict0mem.c - -dict0crea.obj: dict0crea.c - $(CCOM) $(CFL) -c dict0crea.c - -dict0load.obj: dict0load.c - $(CCOM) $(CFL) -c dict0load.c - - |