diff options
author | unknown <monty@donna.mysql.com> | 2001-02-17 14:19:19 +0200 |
---|---|---|
committer | unknown <monty@donna.mysql.com> | 2001-02-17 14:19:19 +0200 |
commit | 2662b59306ef0cd495fa6e2edf7129e58a11393a (patch) | |
tree | bfe39951a73e906579ab819bf5198ad8f3a64a36 /innobase/dict | |
parent | 66de55a56bdcf2f7a9c0c4f8e19b3e761475e202 (diff) | |
download | mariadb-git-2662b59306ef0cd495fa6e2edf7129e58a11393a.tar.gz |
Added Innobase to source distribution
Docs/manual.texi:
Added Innobase documentation
configure.in:
Incremented version
include/my_base.h:
Added option for Innobase
myisam/mi_check.c:
cleanup
mysql-test/t/bdb.test:
cleanup
mysql-test/t/innobase.test:
Extended with new tests from bdb.test
mysql-test/t/merge.test:
Added test of SHOW create
mysys/my_init.c:
Fix for UNIXWARE 7
scripts/mysql_install_db.sh:
Always write how to start mysqld
scripts/safe_mysqld.sh:
Fixed type
sql/ha_innobase.cc:
Update to new version
sql/ha_innobase.h:
Update to new version
sql/handler.h:
Added 'update_table_comment()' and 'append_create_info()'
sql/sql_delete.cc:
Fixes for Innobase
sql/sql_select.cc:
Fixes for Innobase
sql/sql_show.cc:
Append create information (for MERGE tables)
sql/sql_update.cc:
Fixes for Innobase
Diffstat (limited to 'innobase/dict')
-rw-r--r-- | innobase/dict/Makefile.am | 25 | ||||
-rw-r--r-- | innobase/dict/dict0boot.c | 361 | ||||
-rw-r--r-- | innobase/dict/dict0crea.c | 1031 | ||||
-rw-r--r-- | innobase/dict/dict0dict.c | 1870 | ||||
-rw-r--r-- | innobase/dict/dict0load.c | 611 | ||||
-rw-r--r-- | innobase/dict/dict0mem.c | 291 | ||||
-rw-r--r-- | innobase/dict/makefilewin | 21 | ||||
-rw-r--r-- | innobase/dict/ts/makefile | 16 | ||||
-rw-r--r-- | innobase/dict/ts/tsdict.c | 73 |
9 files changed, 4299 insertions, 0 deletions
diff --git a/innobase/dict/Makefile.am b/innobase/dict/Makefile.am new file mode 100644 index 00000000000..693048b6784 --- /dev/null +++ b/innobase/dict/Makefile.am @@ -0,0 +1,25 @@ +# 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 + +libs_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 new file mode 100644 index 00000000000..260e8d4c276 --- /dev/null +++ b/innobase/dict/dict0boot.c @@ -0,0 +1,361 @@ +/****************************************************** +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" + +/************************************************************************** +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; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + id = dict_sys->row_id; + + mtr_start(&mtr); + + dict_hdr = dict_hdr_get(&mtr); + + mlog_write_dulint(dict_hdr + DICT_HDR_ROW_ID, id, MLOG_8BYTES, &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), + MLOG_8BYTES, mtr); + + mlog_write_dulint(dict_header + DICT_HDR_TABLE_ID, + ut_dulint_create(0, DICT_HDR_FIRST_ID), + MLOG_8BYTES, mtr); + + mlog_write_dulint(dict_header + DICT_HDR_INDEX_ID, + ut_dulint_create(0, DICT_HDR_FIRST_ID), + MLOG_8BYTES, mtr); + + mlog_write_dulint(dict_header + DICT_HDR_MIX_ID, + ut_dulint_create(0, DICT_HDR_FIRST_ID), + MLOG_8BYTES, 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, 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, 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, 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, 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, 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; + + 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, + MLOG_8BYTES, &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); + + 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); + + index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_TABLES, + MLOG_4BYTES, &mtr); + index->id = DICT_TABLES_ID; + + ut_a(dict_index_add_to_cache(table, index)); + /*-------------------------*/ + index = dict_mem_index_create("SYS_TABLES", "ID_IND", DICT_HDR_SPACE, + DICT_UNIQUE, 1); + dict_mem_index_add_field(index, "ID", 0); + + index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_TABLE_IDS, + MLOG_4BYTES, &mtr); + index->id = DICT_TABLE_IDS_ID; + ut_a(dict_index_add_to_cache(table, index)); + /*-------------------------*/ + table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7); + + 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); + dict_mem_index_add_field(index, "POS", 0); + + index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_COLUMNS, + MLOG_4BYTES, &mtr); + index->id = DICT_COLUMNS_ID; + ut_a(dict_index_add_to_cache(table, index)); + /*-------------------------*/ + table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7); + + 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 */ + ut_ad(DICT_SYS_INDEXES_PAGE_NO_FIELD == 6 + 2); + ut_ad(DICT_SYS_INDEXES_SPACE_NO_FIELD == 5 + 2); + + 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); + dict_mem_index_add_field(index, "ID", 0); + + index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_INDEXES, + MLOG_4BYTES, &mtr); + index->id = DICT_INDEXES_ID; + ut_a(dict_index_add_to_cache(table, index)); + /*-------------------------*/ + table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3); + + 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); + dict_mem_index_add_field(index, "POS", 0); + + index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_FIELDS, + MLOG_4BYTES, &mtr); + index->id = DICT_FIELDS_ID; + ut_a(dict_index_add_to_cache(table, index)); + + mtr_commit(&mtr); + /*-------------------------*/ + /* 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); + + /* Initialize the insert buffer table and index for each tablespace */ + + ibuf_init_at_db_start(); + + 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(); + + sync_order_checks_on = TRUE; +} diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c new file mode 100644 index 00000000000..37967361570 --- /dev/null +++ b/innobase/dict/dict0crea.c @@ -0,0 +1,1031 @@ +/****************************************************** +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 "que0que.h" +#include "row0ins.h" +#include "pars0pars.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 */ +/********************************************************************* +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 */ +/********************************************************************* +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 */ + trx_t* trx); /* in: transaction handle */ +/********************************************************************* +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 */ +/********************************************************************* +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 */ +/************************************************************************* +Creates the single index for a cluster: it contains all the columns of +the cluster definition in the order they were defined. */ +static +void +dict_create_cluster_index( +/*======================*/ + dict_table_t* table, /* in: cluster */ + trx_t* trx); /* in: transaction handle */ + + +/********************************************************************* +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); + + 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)); + } 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; + + UT_NOT_USED(thr); + ut_ad(mutex_own(&(dict_sys->mutex))); + + table = node->table; + + table->id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); + + thr_get_trx(thr)->table_id = table->id; + + 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); + } + + 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); +} + +#ifdef notdefined + +/************************************************************************* +Creates the single index for a cluster: it contains all the columns of +the cluster definition in the order they were defined. */ +static +void +dict_create_index_for_cluster_step( +/*===============================*/ + tab_node_t* node) /* in: table create node */ +{ + dict_index_t* index; + ulint i; + dict_col_t* col; + + index = dict_mem_index_create(table->name, "IND_DEFAULT_CLUSTERED", + table->space, DICT_CLUSTERED, + table->n_cols); + + for (i = 0; i < table->n_cols; i++) { + col = dict_table_get_nth_col(table, i); + dict_mem_index_add_field(index, col->name, 0); + } + + (node->cluster)->index = index; +} +#endif + +/********************************************************************* +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 */ + trx_t* trx) /* in: transaction handle */ +{ + dict_table_t* sys_indexes; + dict_table_t* table; + dtuple_t* entry; + dfield_t* dfield; + byte* ptr; + + UT_NOT_USED(trx); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(index && heap); + + sys_indexes = dict_sys->sys_indexes; + + table = dict_table_get_low(index->table_name); + + entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS); + + /* 0: TABLE_ID -----------------------*/ + dfield = dtuple_get_nth_field(entry, 0); + + ptr = mem_heap_alloc(heap, 8); + mach_write_to_8(ptr, table->id); + + dfield_set_data(dfield, ptr, 8); + /* 1: ID ----------------------------*/ + dfield = dtuple_get_nth_field(entry, 1); + + ptr = mem_heap_alloc(heap, 8); + mach_write_to_8(ptr, index->id); + + dfield_set_data(dfield, ptr, 8); + /* 4: NAME --------------------------*/ + dfield = dtuple_get_nth_field(entry, 2); + + dfield_set_data(dfield, index->name, ut_strlen(index->name)); + /* 5: N_FIELDS ----------------------*/ + dfield = dtuple_get_nth_field(entry, 3); + + ptr = mem_heap_alloc(heap, 4); + mach_write_to_4(ptr, index->n_fields); + + dfield_set_data(dfield, ptr, 4); + /* 6: TYPE --------------------------*/ + dfield = dtuple_get_nth_field(entry, 4); + + ptr = mem_heap_alloc(heap, 4); + mach_write_to_4(ptr, index->type); + + dfield_set_data(dfield, ptr, 4); + /* 7: SPACE --------------------------*/ + + ut_a(DICT_SYS_INDEXES_SPACE_NO_FIELD == 7); + + 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 --------------------------*/ + + ut_a(DICT_SYS_INDEXES_PAGE_NO_FIELD == 8); + + 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; + + ut_ad(index && heap); + + 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 ----------------------------*/ + 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: 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; + + UT_NOT_USED(thr); + ut_ad(mutex_own(&(dict_sys->mutex))); + + index = node->index; + + table = dict_table_get_low(index->table_name); + + if (table == NULL) { + return(DB_TABLE_NOT_FOUND); + } + + thr_get_trx(thr)->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); + + if (index->type & DICT_CLUSTERED) { + /* Inherit the space from the table */ + index->space = table->space; + } + + index->page_no = FIL_NULL; + + row = dict_create_sys_indexes_tuple(index, node->heap, + thr_get_trx(thr)); + 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 */ + que_thr_t* thr, /* in: query thread */ + ind_node_t* node) /* in: index create node */ +{ + dict_index_t* index; + dict_table_t* sys_indexes; + dict_table_t* table; + dtuple_t* search_tuple; + btr_pcur_t pcur; + mtr_t mtr; + + ut_ad(mutex_own(&(dict_sys->mutex))); + UT_NOT_USED(thr); + + 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); + + index->page_no = btr_create(index->type, index->space, index->id, + &mtr); + page_rec_write_index_page_no(btr_pcur_get_rec(&pcur), + DICT_SYS_INDEXES_PAGE_NO_FIELD, + index->page_no, &mtr); + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + if (index->page_no == FIL_NULL) { + + return(DB_OUT_OF_FILE_SPACE); + } + + return(DB_SUCCESS); +} + +/*********************************************************************** +Drops the index tree associated with a row in SYS_INDEXES table. */ + +void +dict_drop_index_tree( +/*=================*/ + rec_t* rec, /* in: record in the clustered index of SYS_INDEXES + table */ + mtr_t* mtr) /* in: mtr having the latch on the record page */ +{ + ulint root_page_no; + ulint space; + byte* ptr; + ulint len; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + ptr = rec_get_nth_field(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(rec, DICT_SYS_INDEXES_SPACE_NO_FIELD, &len); + + ut_ad(len == 4); + + space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr); + + /* 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 */ + + btr_free_root(space, root_page_no, mtr); + + page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, + FIL_NULL, mtr); +} + +#ifdef notdefined +/************************************************************************* +Creates the default clustered index for a table: the records are ordered +by row id. */ + +void +dict_create_default_index( +/*======================*/ + dict_table_t* table, /* in: table */ + trx_t* trx) /* in: transaction handle */ +{ + dict_index_t* index; + + index = dict_mem_index_create(table->name, "IND_DEFAULT_CLUSTERED", + table->space, DICT_CLUSTERED, 0); + + dict_create_index(index, trx); +} + +#endif + +/************************************************************************* +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->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; + trx_t* trx; + + ut_ad(thr); + ut_ad(mutex_own(&(dict_sys->mutex))); + + trx = thr_get_trx(thr); + + node = thr->run_node; + + ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_TABLE); + + if (thr->prev_node == que_node_get_parent(node)) { + node->state = TABLE_BUILD_TABLE_DEF; + } + + if (node->state == TABLE_BUILD_TABLE_DEF) { + + /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */ + + err = dict_build_table_def_step(thr, node); + + if (err != DB_SUCCESS) { + + goto function_exit; + } + + node->state = TABLE_BUILD_COL_DEF; + node->col_no = 0; + + thr->run_node = node->tab_def; + + return(thr); + } + + if (node->state == TABLE_BUILD_COL_DEF) { + + if (node->col_no < (node->table)->n_def) { + + err = dict_build_col_def_step(node); + + if (err != DB_SUCCESS) { + + goto function_exit; + } + + node->col_no++; + + thr->run_node = node->col_def; + + return(thr); + } else { + node->state = TABLE_COMMIT_WORK; + } + } + + if (node->state == TABLE_COMMIT_WORK) { + + /* Table was correctly defined: do NOT commit the transaction + (CREATE TABLE does NOT do an implicit commit of the current + transaction) */ + + node->state = TABLE_ADD_TO_CACHE; + + /* thr->run_node = node->commit_node; + + return(thr); */ + } + + if (node->state == TABLE_ADD_TO_CACHE) { + + dict_table_add_to_cache(node->table); + + 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; + trx_t* trx; + + ut_ad(thr); + ut_ad(mutex_own(&(dict_sys->mutex))); + + trx = thr_get_trx(thr); + + node = thr->run_node; + + ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_INDEX); + + if (thr->prev_node == que_node_get_parent(node)) { + node->state = INDEX_BUILD_INDEX_DEF; + } + + if (node->state == INDEX_BUILD_INDEX_DEF) { + /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */ + err = dict_build_index_def_step(thr, node); + + if (err != DB_SUCCESS) { + + goto function_exit; + } + + node->state = INDEX_BUILD_FIELD_DEF; + node->field_no = 0; + + thr->run_node = node->ind_def; + + return(thr); + } + + if (node->state == INDEX_BUILD_FIELD_DEF) { + + if (node->field_no < (node->index)->n_fields) { + + err = dict_build_field_def_step(node); + + if (err != DB_SUCCESS) { + + goto function_exit; + } + + node->field_no++; + + thr->run_node = node->field_def; + + return(thr); + } else { + node->state = INDEX_CREATE_INDEX_TREE; + } + } + + if (node->state == INDEX_CREATE_INDEX_TREE) { + + err = dict_create_index_tree_step(thr, 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); + + 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); +} diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c new file mode 100644 index 00000000000..098d34c70e3 --- /dev/null +++ b/innobase/dict/dict0dict.c @@ -0,0 +1,1870 @@ +/********************************************************************** +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 "trx0undo.h" +#include "btr0btr.h" +#include "btr0sea.h" +#include "pars0pars.h" +#include "pars0sym.h" +#include "que0que.h" + + +dict_sys_t* dict_sys = NULL; /* the dictionary system */ + +#define DICT_HEAP_SIZE 100 /* initial memory heap size when + creating a table or index object */ +#define DICT_POOL_PER_PROCEDURE_HASH 512 /* buffer pool max size per stored + procedure hash table fixed size in + bytes */ +#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 */ + +/************************************************************************** +Frees tables from the end of table_LRU if the dictionary cache occupies +too much space. */ +static +void +dict_table_LRU_trim(void); +/*=====================*/ +/************************************************************************** +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 */ + 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 */ +/*********************************************************************** +Adds a column to index. */ +UNIV_INLINE +void +dict_index_add_col( +/*===============*/ + dict_index_t* index, /* in: index */ + dict_col_t* col, /* in: column */ + ulint order); /* in: order criterion */ +/*********************************************************************** +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 */ +/************************************************************************** +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 */ +/************************************************************************** +Prints a table data. */ +static +void +dict_table_print_low( +/*=================*/ + dict_table_t* table); /* in: table */ +/************************************************************************** +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 */ + +/************************************************************************ +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)); +} + +/************************************************************************ +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 */ + char* name) /* in: index name */ +{ + return(dict_table_get_index(table, name)); +} + +/************************************************************************ +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); + + if (index->type & DICT_CLUSTERED) { + col = dict_table_get_nth_col(index->table, n); + + 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); + col = field->col; + + if (dict_col_get_no(col) == n) { + + 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) { + /* 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! */ + + ut_ad(mutex_own(&(dict_sys->mutex))); + + 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 postion 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)); +} + +/************************************************************************** +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->procedure_hash = hash_create(buf_pool_get_max_size() / + (DICT_POOL_PER_PROCEDURE_HASH * + UNIV_WORD_SIZE)); + dict_sys->size = 0; + + UT_LIST_INIT(dict_sys->table_LRU); +} + +/************************************************************************** +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 */ + 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_last_estimate_counter == (ulint)(-1)) { + 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); + ut_ad(mutex_own(&(dict_sys->mutex))); + 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, 0, 0); + ut_ad(DATA_ROW_ID == 0); + dict_mem_table_add_col(table, "DB_TRX_ID", DATA_SYS, DATA_TRX_ID, 0, 0); + ut_ad(DATA_TRX_ID == 1); + dict_mem_table_add_col(table, "DB_ROLL_PTR", DATA_SYS, DATA_ROLL_PTR, + 0, 0); + ut_ad(DATA_ROLL_PTR == 2); + + dict_mem_table_add_col(table, "DB_MIX_ID", DATA_SYS, DATA_MIX_ID, 0, 0); + ut_ad(DATA_MIX_ID == 3); + ut_ad(DATA_N_SYS_COLS == 4); /* This assert reminds that if a new + system column is added to the program, + it should be dealt with here */ + + /* 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(); */ +} + +/************************************************************************** +Renames a table object. */ + +ibool +dict_table_rename_in_cache( +/*=======================*/ + /* out: TRUE if success */ + dict_table_t* table, /* in: table */ + char* new_name) /* in: new name */ +{ + ulint fold; + ulint old_size; + char* name_buf; + ulint i; + + ut_ad(table); + ut_ad(mutex_own(&(dict_sys->mutex))); + + 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) { + 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); + + name_buf = mem_heap_alloc(table->heap, ut_strlen(new_name) + 1); + + ut_memcpy(name_buf, new_name, ut_strlen(new_name) + 1); + + table->name = name_buf; + + /* 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); + + return(TRUE); +} + +/************************************************************************** +Removes a table object from the dictionary cache. */ + +void +dict_table_remove_from_cache( +/*=========================*/ + dict_table_t* table) /* in, own: table */ +{ + dict_index_t* index; + ulint size; + ulint i; + + ut_ad(table); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + /* printf("Removing table %s from dictionary cache\n", table->name); */ + + /* 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); + + 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! */ +static +void +dict_table_LRU_trim(void) +/*=====================*/ +{ + dict_table_t* table; + dict_table_t* prev_table; + + ut_a(0); + + ut_ad(mutex_own(&(dict_sys->mutex))); + + 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); + ut_ad(mutex_own(&(dict_sys->mutex))); + 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); + ut_ad(mutex_own(&(dict_sys->mutex))); + 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 */ + char* new_name) /* in: new table name */ +{ + ulint fold; + + ut_ad(table && col); + ut_ad(mutex_own(&(dict_sys->mutex))); + 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! */ +{ + 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); + ut_ad(mutex_own(&(dict_sys->mutex))); + 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; + new_index->page_no = tree->page; + } else { + /* Create an index tree memory object for the index */ + tree = dict_tree_create(new_index); + ut_ad(tree); + + new_index->tree = tree; + } + + /* 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); + ut_ad(mutex_own(&(dict_sys->mutex))); + + 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); + ut_ad(mutex_own(&(dict_sys->mutex))); + + 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. */ +UNIV_INLINE +void +dict_index_add_col( +/*===============*/ + dict_index_t* index, /* in: index */ + dict_col_t* col, /* in: column */ + ulint order) /* in: order criterion */ +{ + dict_field_t* field; + + dict_mem_index_add_field(index, col->name, order); + + field = dict_index_get_nth_field(index, index->n_def - 1); + + field->col = col; +} + +/*********************************************************************** +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); + } +} + +/*********************************************************************** +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); + ut_ad(mutex_own(&(dict_sys->mutex))); + 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; + new_index->page_no = index->page_no; + + 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); + + /* 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); + trx_id_pos++; + } + + dict_index_add_col(new_index, + dict_table_get_sys_col(table, DATA_TRX_ID), 0); + dict_index_add_col(new_index, + dict_table_get_sys_col(table, DATA_ROLL_PTR), 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; + } + + 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); + (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); + } + } + + 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); + (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)); + ut_ad(mutex_own(&(dict_sys->mutex))); + 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; + new_index->page_no = index->page_no; + + /* 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); + (field->col)->aux = 0; + } + + /* Add to new_index 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); + } + } + + 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); +} + +/************************************************************************** +Adds a stored procedure object to the dictionary cache. */ + +void +dict_procedure_add_to_cache( +/*========================*/ + dict_proc_t* proc) /* in: procedure */ +{ + ulint fold; + + mutex_enter(&(dict_sys->mutex)); + + fold = ut_fold_string(proc->name); + + /* Look for a procedure with the same name: error if such exists */ + { + dict_proc_t* proc2; + + HASH_SEARCH(name_hash, dict_sys->procedure_hash, fold, proc2, + (ut_strcmp(proc2->name, proc->name) == 0)); + ut_a(proc2 == NULL); + } + + /* Add the procedure to the hash table */ + + HASH_INSERT(dict_proc_t, name_hash, dict_sys->procedure_hash, fold, + proc); + mutex_exit(&(dict_sys->mutex)); +} + +/************************************************************************** +Reserves a parsed copy of a stored procedure to execute. If there are no +free parsed copies left at the moment, parses a new copy. Takes the copy off +the list of copies: the copy must be returned there with +dict_procedure_release_parsed_copy. */ + +que_t* +dict_procedure_reserve_parsed_copy( +/*===============================*/ + /* out: the query graph */ + dict_proc_t* proc) /* in: dictionary procedure node */ +{ + que_t* graph; + proc_node_t* proc_node; + + ut_ad(!mutex_own(&kernel_mutex)); + + mutex_enter(&(dict_sys->mutex)); + +#ifdef UNIV_DEBUG + UT_LIST_VALIDATE(graphs, que_t, proc->graphs); +#endif + graph = UT_LIST_GET_FIRST(proc->graphs); + + if (graph) { + UT_LIST_REMOVE(graphs, proc->graphs, graph); + +/* printf("Graph removed, list length %lu\n", + UT_LIST_GET_LEN(proc->graphs)); */ +#ifdef UNIV_DEBUG + UT_LIST_VALIDATE(graphs, que_t, proc->graphs); +#endif + } + + mutex_exit(&(dict_sys->mutex)); + + if (graph == NULL) { + graph = pars_sql(proc->sql_string); + + proc_node = que_fork_get_child(graph); + + proc_node->dict_proc = proc; + + printf("Parsed a new copy of graph %s\n", + proc_node->proc_id->name); + } + +/* printf("Returning graph %lu\n", (ulint)graph); */ + + return(graph); +} + +/************************************************************************** +Releases a parsed copy of an executed stored procedure. Puts the copy to the +list of copies. */ + +void +dict_procedure_release_parsed_copy( +/*===============================*/ + que_t* graph) /* in: query graph of a stored procedure */ +{ + proc_node_t* proc_node; + + ut_ad(!mutex_own(&kernel_mutex)); + + mutex_enter(&(dict_sys->mutex)); + + proc_node = que_fork_get_child(graph); + + UT_LIST_ADD_FIRST(graphs, (proc_node->dict_proc)->graphs, graph); + + mutex_exit(&(dict_sys->mutex)); +} + +/************************************************************************** +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 */ +{ + 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 = index->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_ad(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 */ + + mix_id = mach_dulint_read_compressed( + rec_get_nth_field(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 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 */ +{ + 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 */ + + n_unique = rec_get_n_fields(rec); + } 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, 0, 0, 0); + + rec_copy_prefix_to_dtuple(tuple, rec, n_unique, heap); + + 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 */ + byte** buf, /* in/out: memory buffer for the copied prefix, + or NULL */ + ulint* buf_size)/* in/out: buffer size */ +{ + dict_index_t* ind; + rec_t* order_rec; + ulint n_fields; + + ind = dict_tree_find_index_low(tree, rec); + + n_fields = dict_index_get_n_unique_in_tree(ind); + + if (tree->type & DICT_UNIVERSAL) { + + n_fields = rec_get_n_fields(rec); + } + + order_rec = rec_copy_prefix_to_buf(rec, n_fields, buf, buf_size); + + return(order_rec); +} + +/************************************************************************** +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 */ + mem_heap_t* heap) /* in: memory heap where tuple created */ +{ + dtuple_t* tuple; + dict_index_t* ind; + ulint n_fields; + + ind = dict_tree_find_index_low(tree, rec); + + n_fields = rec_get_n_fields(rec); + + tuple = dtuple_create(heap, n_fields); + + dict_index_copy_types(tuple, ind, n_fields); + + rec_copy_prefix_to_dtuple(tuple, rec, n_fields, heap); + + ut_ad(dtuple_check_typed(tuple)); + + return(tuple); +} + +/************************************************************************* +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 */ +{ + mem_heap_t* heap; + dict_index_t* index; + dtuple_t* start; + dtuple_t* end; + ulint n_rows; + ulint n_vals; + ulint size; + ulint sum_of_index_sizes = 0; + + /* Estimate the number of records in the clustered index */ + index = dict_table_get_first_index(table); + + heap = mem_heap_create(500); + + start = dtuple_create(heap, 0); + end = dtuple_create(heap, 0); + + n_rows = btr_estimate_n_rows_in_range(index, start, PAGE_CUR_G, + end, PAGE_CUR_L); + mem_heap_free(heap); + + if (n_rows > 0) { + /* For small tables our estimate function tends to give + values 1 too big */ + n_rows--; + } + + mutex_enter(&(dict_sys->mutex)); + + table->stat_last_estimate_counter = table->stat_modif_counter; + table->stat_n_rows = n_rows; + + mutex_exit(&(dict_sys->mutex)); + + /* Find out the sizes of the indexes and how many different values + for the key they approximately have */ + + while (index) { + n_vals = btr_estimate_number_of_different_key_vals(index); + size = btr_get_size(index, BTR_TOTAL_SIZE); + + sum_of_index_sizes += size; + + mutex_enter(&(dict_sys->mutex)); + + index->stat_n_diff_key_vals = n_vals; + index->stat_index_size = size; + + mutex_exit(&(dict_sys->mutex)); + + index = dict_table_get_next_index(index); + } + + index = dict_table_get_first_index(table); + + 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_last_estimate_counter = table->stat_modif_counter; +} + +/************************************************************************** +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( +/*=====================*/ + 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. */ +static +void +dict_table_print_low( +/*=================*/ + dict_table_t* table) /* in: table */ +{ + ulint i; + dict_index_t* index; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + printf("--------------------------------------\n"); + printf("TABLE INFO: name %s, columns %lu, indexes %lu\n", table->name, + table->n_cols, UT_LIST_GET_LEN(table->indexes)); + for (i = 0; i < table->n_cols; i++) { + printf(" "); + dict_col_print_low(dict_table_get_nth_col(table, i)); + } + + index = UT_LIST_GET_FIRST(table->indexes); + + while (index != NULL) { + dict_index_print_low(index); + index = UT_LIST_GET_NEXT(indexes, index); + } +} + +/************************************************************************** +Prints a column data. */ +static +void +dict_col_print_low( +/*===============*/ + dict_col_t* col) /* in: column */ +{ + dtype_t* type; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + type = dict_col_get_type(col); + printf("COLUMN: name %s; ", col->name); + + dtype_print(type); +} + +/************************************************************************** +Prints an index data. */ +static +void +dict_index_print_low( +/*=================*/ + dict_index_t* index) /* in: index */ +{ + ulint i; + dict_tree_t* tree; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + tree = index->tree; + + printf( + "INDEX INFO: name %s, table name %s, fields %lu, type %lu\n", + index->name, index->table_name, index->n_fields, + index->type); + printf(" root node: space %lu, page number %lu\n", + tree->space, tree->page); + + for (i = 0; i < index->n_fields; i++) { + printf(" "); + dict_field_print_low(dict_index_get_nth_field(index, i)); + } + + 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 */ +{ + ut_ad(mutex_own(&(dict_sys->mutex))); + + printf("FIELD: column name %s, order criterion %lu\n", field->name, + field->order); +} diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c new file mode 100644 index 00000000000..be16988086a --- /dev/null +++ b/innobase/dict/dict0load.c @@ -0,0 +1,611 @@ +/****************************************************** +Loads to the memory cache database object definitions +from dictionary tables + +(c) 1996 Innobase Oy + +Created 4/24/1996 Heikki Tuuri +*******************************************************/ + +#include "dict0load.h" + +#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" + +/************************************************************************ +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 */ +/************************************************************************ +Loads definitions for table indexes. */ +static +void +dict_load_indexes( +/*==============*/ + dict_table_t* table, /* in: table */ + mem_heap_t* heap); /* in: memory heap for temporary storage */ +/************************************************************************ +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 */ + + +/************************************************************************ +Loads a table definition and also all its index definitions, and also +the cluster definition if the table is a member in a cluster. */ + +dict_table_t* +dict_load_table( +/*============*/ + /* out: table, NULL if does not exist */ + char* name) /* in: table name */ +{ + dict_table_t* table; + dict_table_t* sys_tables; + mtr_t mtr; + 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; + char* buf; + ulint space; + ulint n_cols; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + 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); + + 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)) { + /* Not found */ + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + return(NULL); + } + + field = rec_get_nth_field(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( + dict_table_get_first_index(sys_tables), 9))->name)); + + field = rec_get_nth_field(rec, 9, &len); + space = mach_read_from_4(field); + + ut_a(0 == ut_strcmp("N_COLS", + dict_field_get_col( + dict_index_get_nth_field( + dict_table_get_first_index(sys_tables), 4))->name)); + + field = rec_get_nth_field(rec, 4, &len); + n_cols = mach_read_from_4(field); + + table = dict_mem_table_create(name, space, n_cols); + + ut_a(0 == ut_strcmp("ID", + dict_field_get_col( + dict_index_get_nth_field( + dict_table_get_first_index(sys_tables), 3))->name)); + + field = rec_get_nth_field(rec, 3, &len); + table->id = mach_read_from_8(field); + + field = rec_get_nth_field(rec, 5, &len); + table->type = mach_read_from_4(field); + + if (table->type == DICT_TABLE_CLUSTER_MEMBER) { + ut_a(0); + + field = rec_get_nth_field(rec, 6, &len); + table->mix_id = mach_read_from_8(field); + + field = rec_get_nth_field(rec, 8, &len); + buf = mem_heap_alloc(heap, len); + ut_memcpy(buf, field, len); + + table->cluster_name = buf; + } + + if ((table->type == DICT_TABLE_CLUSTER) + || (table->type == DICT_TABLE_CLUSTER_MEMBER)) { + + field = rec_get_nth_field(rec, 7, &len); + 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); + + 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; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + heap = mem_heap_create(1000); + + dict_load_indexes(table, heap); + + mem_heap_free(heap); +} + +/************************************************************************ +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_buf; + char* name; + ulint mtype; + ulint prtype; + ulint col_len; + ulint prec; + ulint i; + mtr_t mtr; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + mtr_start(&mtr); + + sys_columns = dict_table_get_low("SYS_COLUMNS"); + sys_index = UT_LIST_GET_FIRST(sys_columns->indexes); + + 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)); + + field = rec_get_nth_field(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(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( + dict_table_get_first_index(sys_columns), 4))->name)); + + field = rec_get_nth_field(rec, 4, &len); + + name_buf = mem_heap_alloc(heap, len + 1); + ut_memcpy(name_buf, field, len); + name_buf[len] = '\0'; + + name = name_buf; + + field = rec_get_nth_field(rec, 5, &len); + mtype = mach_read_from_4(field); + + field = rec_get_nth_field(rec, 6, &len); + prtype = mach_read_from_4(field); + + field = rec_get_nth_field(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( + dict_table_get_first_index(sys_columns), 8))->name)); + + field = rec_get_nth_field(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); +} + +/************************************************************************ +Loads definitions for table indexes. */ +static +void +dict_load_indexes( +/*==============*/ + 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; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + 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); + + 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(rec, 0, &len); + ut_ad(len == 8); + + if (ut_memcmp(buf, field, len) != 0) { + break; + } + + ut_a(!rec_get_deleted_flag(rec)); + + field = rec_get_nth_field(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( + dict_table_get_first_index(sys_indexes), 4))->name)); + + field = rec_get_nth_field(rec, 4, &name_len); + + name_buf = mem_heap_alloc(heap, name_len + 1); + ut_memcpy(name_buf, field, name_len); + name_buf[name_len] = '\0'; + + field = rec_get_nth_field(rec, 5, &len); + n_fields = mach_read_from_4(field); + + field = rec_get_nth_field(rec, 6, &len); + type = mach_read_from_4(field); + + field = rec_get_nth_field(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( + dict_table_get_first_index(sys_indexes), 8))->name)); + + field = rec_get_nth_field(rec, 8, &len); + page_no = mach_read_from_4(field); + + if (is_sys_table + && ((type & DICT_CLUSTERED) + || ((table == dict_sys->sys_tables) + && (name_len == ut_strlen("ID_IND")) + && (0 == ut_memcmp(name_buf, "ID_IND", + name_len))))) { + + /* The index was created in memory already in + booting */ + } else { + index = dict_mem_index_create(table->name, name_buf, + space, type, n_fields); + index->page_no = page_no; + index->id = id; + + dict_load_fields(table, index, heap); + + dict_index_add_to_cache(table, index); + } + + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + } + + btr_pcur_close(&pcur); + mtr_commit(&mtr); +} + +/************************************************************************ +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; + mtr_t mtr; + btr_pcur_t pcur; + dtuple_t* tuple; + dfield_t* dfield; + char* col_name; + rec_t* rec; + byte* field; + ulint len; + byte* buf; + ulint i; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + UT_NOT_USED(table); + + mtr_start(&mtr); + + sys_fields = dict_table_get_low("SYS_FIELDS"); + sys_index = UT_LIST_GET_FIRST(sys_fields->indexes); + + 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)); + ut_a(!rec_get_deleted_flag(rec)); + + field = rec_get_nth_field(rec, 0, &len); + ut_ad(len == 8); + ut_a(ut_memcmp(buf, field, len) == 0); + + field = rec_get_nth_field(rec, 1, &len); + ut_ad(len == 4); + ut_a(i == mach_read_from_4(field)); + + ut_a(0 == ut_strcmp("COL_NAME", + dict_field_get_col( + dict_index_get_nth_field( + dict_table_get_first_index(sys_fields), 4))->name)); + + field = rec_get_nth_field(rec, 4, &len); + + col_name = mem_heap_alloc(heap, len + 1); + ut_memcpy(col_name, field, len); + col_name[len] = '\0'; + + dict_mem_index_add_field(index, col_name, 0); + + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + } + + btr_pcur_close(&pcur); + mtr_commit(&mtr); +} + +/*************************************************************************** +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 */ +{ + mtr_t mtr; + 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; + char* name; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + /* 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)); + 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)) { + /* 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(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(rec, 1, &len); + + name = mem_heap_alloc(heap, len + 1); + ut_memcpy(name, field, len); + name[len] = '\0'; + + /* Load the table definition to memory */ + table = dict_load_table(name); + + ut_a(table); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + return(table); +} diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c new file mode 100644 index 00000000000..17bc1828388 --- /dev/null +++ b/innobase/dict/dict0mem.c @@ -0,0 +1,291 @@ +/********************************************************************** +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" + +#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 */ + 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 */ +{ + dict_table_t* table; + char* str; + 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; + + str = mem_heap_alloc(heap, 1 + ut_strlen(name)); + + ut_strcpy(str, name); + + table->type = DICT_TABLE_ORDINARY; + table->name = str; + table->space = space; + table->n_def = 0; + table->n_cols = n_cols + DATA_N_SYS_COLS; + table->mem_fix = 0; + table->cached = FALSE; + + table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS) + * sizeof(dict_col_t)); + UT_LIST_INIT(table->indexes); + UT_LIST_INIT(table->locks); + + table->does_not_fit_in_memory = FALSE; + + table->stat_last_estimate_counter = (ulint)(-1); + + table->stat_modif_counter = 0; + + 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 */ + 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; + + cluster = dict_mem_table_create(name, space, n_cols); + + 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 */ + 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 */ + char* name, /* in: column name */ + ulint mtype, /* in: main datatype */ + ulint prtype, /* in: precise type */ + ulint len, /* in: length */ + ulint prec) /* in: precision */ +{ + char* str; + 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); + + str = mem_heap_alloc(table->heap, 1 + ut_strlen(name)); + + ut_strcpy(str, name); + + col->ind = table->n_def - 1; + col->name = str; + 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 */ + char* table_name, /* in: table name */ + 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 */ +{ + char* str; + 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; + + str = mem_heap_alloc(heap, 1 + ut_strlen(index_name)); + + ut_strcpy(str, index_name); + + index->type = type; + index->space = space; + index->name = str; + index->table_name = table_name; + index->table = NULL; + index->n_def = 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->cached = FALSE; + index->magic_n = DICT_INDEX_MAGIC_N; + + return(index); +} + +/************************************************************************** +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 */ + char* name, /* in: column name */ + ulint order) /* in: order criterion; 0 means an ascending + order */ +{ + 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; +} + +/************************************************************************** +Frees an index memory object. */ + +void +dict_mem_index_free( +/*================*/ + dict_index_t* index) /* in: index */ +{ + mem_heap_free(index->heap); +} + +/************************************************************************** +Creates a procedure memory object. */ + +dict_proc_t* +dict_mem_procedure_create( +/*======================*/ + /* out, own: procedure object */ + char* name, /* in: procedure name */ + char* sql_string, /* in: procedure definition as an SQL + string */ + que_fork_t* graph) /* in: parsed procedure graph */ +{ + dict_proc_t* proc; + proc_node_t* proc_node; + mem_heap_t* heap; + char* str; + + ut_ad(name); + + heap = mem_heap_create(128); + + proc = mem_heap_alloc(heap, sizeof(dict_proc_t)); + + proc->heap = heap; + + str = mem_heap_alloc(heap, 1 + ut_strlen(name)); + + ut_strcpy(str, name); + + proc->name = str; + + str = mem_heap_alloc(heap, 1 + ut_strlen(sql_string)); + + ut_strcpy(str, sql_string); + + proc->sql_string = str; + + UT_LIST_INIT(proc->graphs); + +/* UT_LIST_ADD_LAST(graphs, proc->graphs, graph); */ + +#ifdef UNIV_DEBUG + UT_LIST_VALIDATE(graphs, que_t, proc->graphs); +#endif + proc->mem_fix = 0; + + proc_node = que_fork_get_child(graph); + + proc_node->dict_proc = proc; + + return(proc); +} diff --git a/innobase/dict/makefilewin b/innobase/dict/makefilewin new file mode 100644 index 00000000000..e828d06943c --- /dev/null +++ b/innobase/dict/makefilewin @@ -0,0 +1,21 @@ +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 + + diff --git a/innobase/dict/ts/makefile b/innobase/dict/ts/makefile new file mode 100644 index 00000000000..d1a24e90a89 --- /dev/null +++ b/innobase/dict/ts/makefile @@ -0,0 +1,16 @@ + + + +include ..\..\makefile.i + +tsdict: ..\dict.lib tsdict.c + $(CCOM) $(CFL) -I.. -I..\.. ..\dict.lib ..\..\data.lib ..\..\buf.lib ..\..\mach.lib ..\..\fil.lib ..\..\ha.lib ..\..\ut.lib ..\..\sync.lib ..\..\mem.lib ..\..\os.lib tsdict.c $(LFL) + + + + + + + + + diff --git a/innobase/dict/ts/tsdict.c b/innobase/dict/ts/tsdict.c new file mode 100644 index 00000000000..fa41a6b9112 --- /dev/null +++ b/innobase/dict/ts/tsdict.c @@ -0,0 +1,73 @@ +/************************************************************************ +The test module for the data dictionary + +(c) 1996 Innobase Oy + +Created 1/13/1996 Heikki Tuuri +*************************************************************************/ + +#include "sync0sync.h" +#include "mem0mem.h" +#include "buf0buf.h" +#include "data0type.h" +#include "..\dict0dict.h" + +/************************************************************************ +Basic test of data dictionary. */ + +void +test1(void) +/*=======*/ +{ + dict_table_t* table; + dict_index_t* index; + + table = dict_table_create("TS_TABLE1", 3); + + dict_table_add_col(table, "COL1", DATA_INT, 3, 4, 5); + dict_table_add_col(table, "COL2", DATA_INT, 3, 4, 5); + dict_table_add_col(table, "COL3", DATA_INT, 3, 4, 5); + + ut_a(0 == dict_table_publish(table)); + + index = dict_index_create("TS_TABLE1", "IND1", + DICT_UNIQUE | DICT_CLUSTERED | DICT_MIX, 2, 1); + + dict_index_add_field(index, "COL2", DICT_DESCEND); + dict_index_add_field(index, "COL1", 0); + + ut_a(0 == dict_index_publish(index)); + + dict_table_print(table); + + dict_table_free(table); + + ut_a(dict_all_freed()); + + dict_free_all(); + + ut_a(dict_all_freed()); +} + +/************************************************************************ +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + + oldtm = ut_clock(); + + sync_init(); + mem_init(); + buf_pool_init(100, 100); + dict_init(); + + test1(); + + tm = ut_clock(); + printf("Wall clock time for test %lu milliseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} |