summaryrefslogtreecommitdiff
path: root/innobase/dict
diff options
context:
space:
mode:
authorunknown <monty@donna.mysql.com>2001-02-17 14:19:19 +0200
committerunknown <monty@donna.mysql.com>2001-02-17 14:19:19 +0200
commit2662b59306ef0cd495fa6e2edf7129e58a11393a (patch)
treebfe39951a73e906579ab819bf5198ad8f3a64a36 /innobase/dict
parent66de55a56bdcf2f7a9c0c4f8e19b3e761475e202 (diff)
downloadmariadb-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.am25
-rw-r--r--innobase/dict/dict0boot.c361
-rw-r--r--innobase/dict/dict0crea.c1031
-rw-r--r--innobase/dict/dict0dict.c1870
-rw-r--r--innobase/dict/dict0load.c611
-rw-r--r--innobase/dict/dict0mem.c291
-rw-r--r--innobase/dict/makefilewin21
-rw-r--r--innobase/dict/ts/makefile16
-rw-r--r--innobase/dict/ts/tsdict.c73
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");
+}