summaryrefslogtreecommitdiff
path: root/innobase/dict
diff options
context:
space:
mode:
authorunknown <heikki@donna.mysql.fi>2001-10-10 22:47:08 +0300
committerunknown <heikki@donna.mysql.fi>2001-10-10 22:47:08 +0300
commit1904897be71cba7e6f2cf1192ba0cc2e8d907e00 (patch)
treefc361924d14a3d1727a8b88f61352ed039054720 /innobase/dict
parent151ffe886b4b21499471658fdf01ea8347287092 (diff)
downloadmariadb-git-1904897be71cba7e6f2cf1192ba0cc2e8d907e00.tar.gz
ut0mem.c Merge changes in InnoDB-3.23.43b
ut0ut.c Merge changes in InnoDB-3.23.43b trx0purge.c Merge changes in InnoDB-3.23.43b trx0rec.c Merge changes in InnoDB-3.23.43b trx0trx.c Merge changes in InnoDB-3.23.43b trx0undo.c Merge changes in InnoDB-3.23.43b thr0loc.c Merge changes in InnoDB-3.23.43b sync0arr.c Merge changes in InnoDB-3.23.43b sync0rw.c Merge changes in InnoDB-3.23.43b sync0sync.c Merge changes in InnoDB-3.23.43b srv0srv.c Merge changes in InnoDB-3.23.43b srv0start.c Merge changes in InnoDB-3.23.43b row0ins.c Merge changes in InnoDB-3.23.43b row0mysql.c Merge changes in InnoDB-3.23.43b row0purge.c Merge changes in InnoDB-3.23.43b row0sel.c Merge changes in InnoDB-3.23.43b row0umod.c Merge changes in InnoDB-3.23.43b row0upd.c Merge changes in InnoDB-3.23.43b row0vers.c Merge changes in InnoDB-3.23.43b rem0cmp.c Merge changes in InnoDB-3.23.43b que0que.c Merge changes in InnoDB-3.23.43b pars0opt.c Merge changes in InnoDB-3.23.43b pars0pars.c Merge changes in InnoDB-3.23.43b lexyy.c Merge changes in InnoDB-3.23.43b pars0grm.c Merge changes in InnoDB-3.23.43b page0page.c Merge changes in InnoDB-3.23.43b os0file.c Merge changes in InnoDB-3.23.43b mtr0log.c Merge changes in InnoDB-3.23.43b mem0pool.c Merge changes in InnoDB-3.23.43b log0log.c Merge changes in InnoDB-3.23.43b log0recv.c Merge changes in InnoDB-3.23.43b lock0lock.c Merge changes in InnoDB-3.23.43b ibuf0ibuf.c Merge changes in InnoDB-3.23.43b fil0fil.c Merge changes in InnoDB-3.23.43b dict0crea.c Merge changes in InnoDB-3.23.43b dict0dict.c Merge changes in InnoDB-3.23.43b dict0load.c Merge changes in InnoDB-3.23.43b dict0mem.c Merge changes in InnoDB-3.23.43b data0data.c Merge changes in InnoDB-3.23.43b data0type.c Merge changes in InnoDB-3.23.43b buf0buf.c Merge changes in InnoDB-3.23.43b buf0lru.c Merge changes in InnoDB-3.23.43b btr0btr.c Merge changes in InnoDB-3.23.43b btr0cur.c Merge changes in InnoDB-3.23.43b btr0pcur.c Merge changes in InnoDB-3.23.43b btr0sea.c Merge changes in InnoDB-3.23.43b data0type.ic Merge changes in InnoDB-3.23.43b dict0dict.ic Merge changes in InnoDB-3.23.43b mtr0mtr.ic Merge changes in InnoDB-3.23.43b row0upd.ic Merge changes in InnoDB-3.23.43b sync0ipm.ic Merge changes in InnoDB-3.23.43b sync0rw.ic Merge changes in InnoDB-3.23.43b sync0sync.ic Merge changes in InnoDB-3.23.43b trx0rseg.ic Merge changes in InnoDB-3.23.43b btr0pcur.ic Merge changes in InnoDB-3.23.43b buf0buf.ic Merge changes in InnoDB-3.23.43b data0data.ic Merge changes in InnoDB-3.23.43b row0upd.h Merge changes in InnoDB-3.23.43b srv0srv.h Merge changes in InnoDB-3.23.43b sync0arr.h Merge changes in InnoDB-3.23.43b sync0rw.h Merge changes in InnoDB-3.23.43b sync0sync.h Merge changes in InnoDB-3.23.43b trx0trx.h Merge changes in InnoDB-3.23.43b ut0mem.h Merge changes in InnoDB-3.23.43b data0data.h Merge changes in InnoDB-3.23.43b data0type.h Merge changes in InnoDB-3.23.43b db0err.h Merge changes in InnoDB-3.23.43b dict0crea.h Merge changes in InnoDB-3.23.43b dict0dict.h Merge changes in InnoDB-3.23.43b dict0load.h Merge changes in InnoDB-3.23.43b dict0mem.h Merge changes in InnoDB-3.23.43b dict0types.h Merge changes in InnoDB-3.23.43b fil0fil.h Merge changes in InnoDB-3.23.43b ibuf0ibuf.h Merge changes in InnoDB-3.23.43b lock0lock.h Merge changes in InnoDB-3.23.43b log0log.h Merge changes in InnoDB-3.23.43b mtr0mtr.h Merge changes in InnoDB-3.23.43b rem0cmp.h Merge changes in InnoDB-3.23.43b row0ins.h Merge changes in InnoDB-3.23.43b row0mysql.h Merge changes in InnoDB-3.23.43b btr0cur.h Merge changes in InnoDB-3.23.43b btr0pcur.h Merge changes in InnoDB-3.23.43b btr0sea.h Merge changes in InnoDB-3.23.43b buf0buf.h Merge changes in InnoDB-3.23.43b sql_table.cc Merge changes in InnoDB-3.23.43b sql_db.cc Merge changes in InnoDB-3.23.43b ha_innobase.cc Merge changes in InnoDB-3.23.43b handler.cc Merge changes in InnoDB-3.23.43b ha_innobase.h Merge changes in InnoDB-3.23.43b handler.h Merge changes in InnoDB-3.23.43b sql/ha_innobase.h: Merge changes in InnoDB-3.23.43b sql/handler.h: Merge changes in InnoDB-3.23.43b sql/ha_innobase.cc: Merge changes in InnoDB-3.23.43b sql/handler.cc: Merge changes in InnoDB-3.23.43b sql/sql_db.cc: Merge changes in InnoDB-3.23.43b sql/sql_table.cc: Merge changes in InnoDB-3.23.43b innobase/include/btr0cur.h: Merge changes in InnoDB-3.23.43b innobase/include/btr0pcur.h: Merge changes in InnoDB-3.23.43b innobase/include/btr0sea.h: Merge changes in InnoDB-3.23.43b innobase/include/buf0buf.h: Merge changes in InnoDB-3.23.43b innobase/include/data0data.h: Merge changes in InnoDB-3.23.43b innobase/include/data0type.h: Merge changes in InnoDB-3.23.43b innobase/include/db0err.h: Merge changes in InnoDB-3.23.43b innobase/include/dict0crea.h: Merge changes in InnoDB-3.23.43b innobase/include/dict0dict.h: Merge changes in InnoDB-3.23.43b innobase/include/dict0load.h: Merge changes in InnoDB-3.23.43b innobase/include/dict0mem.h: Merge changes in InnoDB-3.23.43b innobase/include/dict0types.h: Merge changes in InnoDB-3.23.43b innobase/include/fil0fil.h: Merge changes in InnoDB-3.23.43b innobase/include/ibuf0ibuf.h: Merge changes in InnoDB-3.23.43b innobase/include/lock0lock.h: Merge changes in InnoDB-3.23.43b innobase/include/log0log.h: Merge changes in InnoDB-3.23.43b innobase/include/mtr0mtr.h: Merge changes in InnoDB-3.23.43b innobase/include/rem0cmp.h: Merge changes in InnoDB-3.23.43b innobase/include/row0ins.h: Merge changes in InnoDB-3.23.43b innobase/include/row0mysql.h: Merge changes in InnoDB-3.23.43b innobase/include/row0upd.h: Merge changes in InnoDB-3.23.43b innobase/include/srv0srv.h: Merge changes in InnoDB-3.23.43b innobase/include/sync0arr.h: Merge changes in InnoDB-3.23.43b innobase/include/sync0rw.h: Merge changes in InnoDB-3.23.43b innobase/include/sync0sync.h: Merge changes in InnoDB-3.23.43b innobase/include/trx0trx.h: Merge changes in InnoDB-3.23.43b innobase/include/ut0mem.h: Merge changes in InnoDB-3.23.43b innobase/include/btr0pcur.ic: Merge changes in InnoDB-3.23.43b innobase/include/buf0buf.ic: Merge changes in InnoDB-3.23.43b innobase/include/data0data.ic: Merge changes in InnoDB-3.23.43b innobase/include/data0type.ic: Merge changes in InnoDB-3.23.43b innobase/include/dict0dict.ic: Merge changes in InnoDB-3.23.43b innobase/include/mtr0mtr.ic: Merge changes in InnoDB-3.23.43b innobase/include/row0upd.ic: Merge changes in InnoDB-3.23.43b innobase/include/sync0ipm.ic: Merge changes in InnoDB-3.23.43b innobase/include/sync0rw.ic: Merge changes in InnoDB-3.23.43b innobase/include/sync0sync.ic: Merge changes in InnoDB-3.23.43b innobase/include/trx0rseg.ic: Merge changes in InnoDB-3.23.43b innobase/btr/btr0btr.c: Merge changes in InnoDB-3.23.43b innobase/btr/btr0cur.c: Merge changes in InnoDB-3.23.43b innobase/btr/btr0pcur.c: Merge changes in InnoDB-3.23.43b innobase/btr/btr0sea.c: Merge changes in InnoDB-3.23.43b innobase/buf/buf0buf.c: Merge changes in InnoDB-3.23.43b innobase/buf/buf0lru.c: Merge changes in InnoDB-3.23.43b innobase/data/data0data.c: Merge changes in InnoDB-3.23.43b innobase/data/data0type.c: Merge changes in InnoDB-3.23.43b innobase/dict/dict0crea.c: Merge changes in InnoDB-3.23.43b innobase/dict/dict0dict.c: Merge changes in InnoDB-3.23.43b innobase/dict/dict0load.c: Merge changes in InnoDB-3.23.43b innobase/dict/dict0mem.c: Merge changes in InnoDB-3.23.43b innobase/fil/fil0fil.c: Merge changes in InnoDB-3.23.43b innobase/ibuf/ibuf0ibuf.c: Merge changes in InnoDB-3.23.43b innobase/lock/lock0lock.c: Merge changes in InnoDB-3.23.43b innobase/log/log0log.c: Merge changes in InnoDB-3.23.43b innobase/log/log0recv.c: Merge changes in InnoDB-3.23.43b innobase/mem/mem0pool.c: Merge changes in InnoDB-3.23.43b innobase/mtr/mtr0log.c: Merge changes in InnoDB-3.23.43b innobase/os/os0file.c: Merge changes in InnoDB-3.23.43b innobase/page/page0page.c: Merge changes in InnoDB-3.23.43b innobase/pars/lexyy.c: Merge changes in InnoDB-3.23.43b innobase/pars/pars0grm.c: Merge changes in InnoDB-3.23.43b innobase/pars/pars0opt.c: Merge changes in InnoDB-3.23.43b innobase/pars/pars0pars.c: Merge changes in InnoDB-3.23.43b innobase/que/que0que.c: Merge changes in InnoDB-3.23.43b innobase/rem/rem0cmp.c: Merge changes in InnoDB-3.23.43b innobase/row/row0ins.c: Merge changes in InnoDB-3.23.43b innobase/row/row0mysql.c: Merge changes in InnoDB-3.23.43b innobase/row/row0purge.c: Merge changes in InnoDB-3.23.43b innobase/row/row0sel.c: Merge changes in InnoDB-3.23.43b innobase/row/row0umod.c: Merge changes in InnoDB-3.23.43b innobase/row/row0upd.c: Merge changes in InnoDB-3.23.43b innobase/row/row0vers.c: Merge changes in InnoDB-3.23.43b innobase/srv/srv0srv.c: Merge changes in InnoDB-3.23.43b innobase/srv/srv0start.c: Merge changes in InnoDB-3.23.43b innobase/sync/sync0arr.c: Merge changes in InnoDB-3.23.43b innobase/sync/sync0rw.c: Merge changes in InnoDB-3.23.43b innobase/sync/sync0sync.c: Merge changes in InnoDB-3.23.43b innobase/thr/thr0loc.c: Merge changes in InnoDB-3.23.43b innobase/trx/trx0purge.c: Merge changes in InnoDB-3.23.43b innobase/trx/trx0rec.c: Merge changes in InnoDB-3.23.43b innobase/trx/trx0trx.c: Merge changes in InnoDB-3.23.43b innobase/trx/trx0undo.c: Merge changes in InnoDB-3.23.43b innobase/ut/ut0mem.c: Merge changes in InnoDB-3.23.43b innobase/ut/ut0ut.c: Merge changes in InnoDB-3.23.43b BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted
Diffstat (limited to 'innobase/dict')
-rw-r--r--innobase/dict/dict0crea.c229
-rw-r--r--innobase/dict/dict0dict.c1020
-rw-r--r--innobase/dict/dict0load.c606
-rw-r--r--innobase/dict/dict0mem.c43
4 files changed, 1772 insertions, 126 deletions
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c
index 478364fba8a..9d79983c9e5 100644
--- a/innobase/dict/dict0crea.c
+++ b/innobase/dict/dict0crea.c
@@ -17,9 +17,13 @@ Created 1/8/1996 Heikki Tuuri
#include "page0page.h"
#include "mach0data.h"
#include "dict0boot.h"
+#include "dict0dict.h"
#include "que0que.h"
#include "row0ins.h"
+#include "row0mysql.h"
#include "pars0pars.h"
+#include "trx0roll.h"
+#include "usr0sess.h"
/*********************************************************************
Based on a table object, this function builds the entry to be inserted
@@ -1019,3 +1023,228 @@ function_exit:
return(thr);
}
+
+/********************************************************************
+Creates the foreign key constraints system tables inside InnoDB
+at database creation or database start if they are not found or are
+not of the right form. */
+
+ulint
+dict_create_or_check_foreign_constraint_tables(void)
+/*================================================*/
+ /* out: DB_SUCCESS or error code */
+{
+ dict_table_t* table1;
+ dict_table_t* table2;
+ que_thr_t* thr;
+ que_t* graph;
+ ulint error;
+ trx_t* trx;
+ char* str;
+
+ mutex_enter(&(dict_sys->mutex));
+
+ table1 = dict_table_get_low("SYS_FOREIGN");
+ table2 = dict_table_get_low("SYS_FOREIGN_COLS");
+
+ if (table1 && table2
+ && UT_LIST_GET_LEN(table1->indexes) == 3
+ && UT_LIST_GET_LEN(table2->indexes) == 1) {
+
+ /* Foreign constraint system tables have already been
+ created, and they are ok */
+
+ mutex_exit(&(dict_sys->mutex));
+
+ return(DB_SUCCESS);
+ }
+
+ trx = trx_allocate_for_mysql();
+
+ trx->op_info = "creating foreign key sys tables";
+
+ if (table1) {
+ fprintf(stderr,
+ "InnoDB: dropping incompletely created SYS_FOREIGN table\n");
+ row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
+ }
+
+ if (table2) {
+ fprintf(stderr,
+ "InnoDB: dropping incompletely created SYS_FOREIGN_COLS table\n");
+ row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
+ }
+
+ fprintf(stderr,
+ "InnoDB: creating foreign key constraint system tables\n");
+
+ /* NOTE: in dict_load_foreigns we use the fact that
+ there are 2 secondary indexes on SYS_FOREIGN, and they
+ are defined just like below */
+
+ str =
+ "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
+ "BEGIN\n"
+ "CREATE TABLE\n"
+ "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT);\n"
+ "CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID);\n"
+ "CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME);\n"
+ "CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME);\n"
+ "CREATE TABLE\n"
+ "SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
+ "CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS);\n"
+ "COMMIT WORK;\n"
+ "END;\n";
+
+ graph = pars_sql(str);
+
+ ut_a(graph);
+
+ graph->trx = trx;
+ trx->graph = NULL;
+
+ graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
+
+ ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
+
+ que_run_threads(thr);
+
+ error = trx->error_state;
+
+ if (error != DB_SUCCESS) {
+ ut_a(error == DB_OUT_OF_FILE_SPACE);
+
+ fprintf(stderr, "InnoDB: creation failed\n");
+ fprintf(stderr, "InnoDB: tablespace is full\n");
+ fprintf(stderr,
+ "InnoDB: dropping incompletely created SYS_FOREIGN tables\n");
+
+ row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
+ row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
+
+ error = DB_MUST_GET_MORE_FILE_SPACE;
+ }
+
+ que_graph_free(graph);
+
+ trx->op_info = "";
+
+ trx_free_for_mysql(trx);
+
+ if (error == DB_SUCCESS) {
+ fprintf(stderr,
+ "InnoDB: foreign key constraint system tables created\n");
+ }
+
+ mutex_exit(&(dict_sys->mutex));
+
+ return(error);
+}
+
+/************************************************************************
+Adds foreign key definitions to data dictionary tables in the database. */
+
+ulint
+dict_create_add_foreigns_to_dictionary(
+/*===================================*/
+ /* out: error code or DB_SUCCESS */
+ dict_table_t* table, /* in: table */
+ trx_t* trx) /* in: transaction */
+{
+ dict_foreign_t* foreign;
+ que_thr_t* thr;
+ que_t* graph;
+ dulint id;
+ ulint len;
+ ulint error;
+ ulint i;
+ char buf2[50];
+ char buf[10000];
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ if (NULL == dict_table_get_low("SYS_FOREIGN")) {
+ fprintf(stderr,
+ "InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
+ return(DB_ERROR);
+ }
+
+ foreign = UT_LIST_GET_FIRST(table->foreign_list);
+loop:
+ if (foreign == NULL) {
+
+ return(DB_SUCCESS);
+ }
+
+ /* Build an InnoDB stored procedure which will insert the necessary
+ rows to SYS_FOREIGN and SYS_FOREIGN_COLS */
+
+ len = 0;
+
+ len += sprintf(buf,
+ "PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n"
+ "BEGIN\n");
+
+ /* We allocate the new id from the sequence of table id's */
+ id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
+
+ sprintf(buf2, "%lu_%lu", ut_dulint_get_high(id),
+ ut_dulint_get_low(id));
+ foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(buf2) + 1);
+ ut_memcpy(foreign->id, buf2, ut_strlen(buf2) + 1);
+
+ len += sprintf(buf + len,
+ "INSERT INTO SYS_FOREIGN VALUES('%lu_%lu', '%s', '%s', %lu);\n",
+ ut_dulint_get_high(id),
+ ut_dulint_get_low(id),
+ table->name,
+ foreign->referenced_table_name,
+ foreign->n_fields);
+
+ for (i = 0; i < foreign->n_fields; i++) {
+
+ len += sprintf(buf + len,
+ "INSERT INTO SYS_FOREIGN_COLS VALUES('%lu_%lu', %lu, '%s', '%s');\n",
+ ut_dulint_get_high(id),
+ ut_dulint_get_low(id),
+ i,
+ foreign->foreign_col_names[i],
+ foreign->referenced_col_names[i]);
+ }
+
+ len += sprintf(buf + len,"COMMIT WORK;\nEND;\n");
+
+ graph = pars_sql(buf);
+
+ ut_a(graph);
+
+ graph->trx = trx;
+ trx->graph = NULL;
+
+ graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
+
+ ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
+
+ que_run_threads(thr);
+
+ error = trx->error_state;
+
+ que_graph_free(graph);
+
+ if (error != DB_SUCCESS) {
+ ut_a(error == DB_OUT_OF_FILE_SPACE);
+
+ fprintf(stderr, "InnoDB: foreign constraint creation failed\n");
+ fprintf(stderr, "InnoDB: tablespace is full\n");
+
+ trx_general_rollback_for_mysql(trx, FALSE, NULL);
+
+ error = DB_MUST_GET_MORE_FILE_SPACE;
+
+ return(error);
+ }
+
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+
+ goto loop;
+}
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index 10d93fc6ecf..e0a7fd327a5 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -17,6 +17,7 @@ Created 1/8/1996 Heikki Tuuri
#include "mach0data.h"
#include "dict0boot.h"
#include "dict0mem.h"
+#include "dict0crea.h"
#include "trx0undo.h"
#include "btr0btr.h"
#include "btr0cur.h"
@@ -24,10 +25,12 @@ Created 1/8/1996 Heikki Tuuri
#include "pars0pars.h"
#include "pars0sym.h"
#include "que0que.h"
-
+#include "rem0cmp.h"
dict_sys_t* dict_sys = NULL; /* the dictionary system */
+rw_lock_t dict_foreign_key_check_lock;
+
#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
@@ -137,12 +140,12 @@ dict_tree_find_index_low(
dict_tree_t* tree, /* in: index tree */
rec_t* rec); /* in: record for which to find correct index */
/**************************************************************************
-Prints a table data. */
+Removes a foreign constraint struct from the dictionet cache. */
static
void
-dict_table_print_low(
-/*=================*/
- dict_table_t* table); /* in: table */
+dict_foreign_remove_from_cache(
+/*===========================*/
+ dict_foreign_t* foreign); /* in, own: foreign constraint */
/**************************************************************************
Prints a column data. */
static
@@ -164,6 +167,13 @@ void
dict_field_print_low(
/*=================*/
dict_field_t* field); /* in: field */
+/*************************************************************************
+Frees a foreign key struct. */
+static
+void
+dict_foreign_free(
+/*==============*/
+ dict_foreign_t* foreign); /* in, own: foreign key struct */
/************************************************************************
Reserves the dictionary system mutex for MySQL. */
@@ -353,7 +363,8 @@ dict_table_get_on_id(
{
dict_table_t* table;
- if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0) {
+ if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
+ || trx->dict_operation) {
/* 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
@@ -415,6 +426,10 @@ dict_init(void)
dict_sys->size = 0;
UT_LIST_INIT(dict_sys->table_LRU);
+
+ rw_lock_create(&dict_foreign_key_check_lock);
+ rw_lock_set_level(&dict_foreign_key_check_lock,
+ SYNC_FOREIGN_KEY_CHECK);
}
/**************************************************************************
@@ -535,6 +550,41 @@ dict_table_add_to_cache(
}
/**************************************************************************
+Looks for an index with the given id. NOTE that we do not reserve
+the dictionary mutex: this function is for emergency purposes like
+printing info of a corrupt database page! */
+
+dict_index_t*
+dict_index_find_on_id_low(
+/*======================*/
+ /* out: index or NULL if not found from cache */
+ dulint id) /* in: index id */
+{
+ dict_table_t* table;
+ dict_index_t* index;
+
+ table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
+
+ while (table) {
+ index = dict_table_get_first_index(table);
+
+ while (index) {
+ if (0 == ut_dulint_cmp(id, index->tree->id)) {
+ /* Found */
+
+ return(index);
+ }
+
+ index = dict_table_get_next_index(index);
+ }
+
+ table = UT_LIST_GET_NEXT(table_LRU, table);
+ }
+
+ return(NULL);
+}
+
+/**************************************************************************
Renames a table object. */
ibool
@@ -544,10 +594,12 @@ dict_table_rename_in_cache(
dict_table_t* table, /* in: table */
char* new_name) /* in: new name */
{
- ulint fold;
- ulint old_size;
- char* name_buf;
- ulint i;
+ dict_foreign_t* foreign;
+ dict_index_t* index;
+ ulint fold;
+ ulint old_size;
+ char* name_buf;
+ ulint i;
ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -589,6 +641,55 @@ dict_table_rename_in_cache(
dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
+ /* Update the table_name field in indexes */
+ index = dict_table_get_first_index(table);
+
+ while (index != NULL) {
+ index->table_name = table->name;
+
+ index = dict_table_get_next_index(index);
+ }
+
+ /* Update the table name fields in foreign constraints */
+
+ foreign = UT_LIST_GET_FIRST(table->foreign_list);
+
+ while (foreign != NULL) {
+ if (ut_strlen(foreign->foreign_table_name) <
+ ut_strlen(table->name)) {
+ /* Allocate a longer name buffer;
+ TODO: store buf len to save memory */
+ foreign->foreign_table_name = mem_heap_alloc(
+ foreign->heap,
+ ut_strlen(table->name) + 1);
+ }
+
+ ut_memcpy(foreign->foreign_table_name, table->name,
+ ut_strlen(table->name) + 1);
+ foreign->foreign_table_name[ut_strlen(table->name)] = '\0';
+
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+
+ foreign = UT_LIST_GET_FIRST(table->referenced_list);
+
+ while (foreign != NULL) {
+ if (ut_strlen(foreign->referenced_table_name) <
+ ut_strlen(table->name)) {
+ /* Allocate a longer name buffer;
+ TODO: store buf len to save memory */
+ foreign->referenced_table_name = mem_heap_alloc(
+ foreign->heap,
+ ut_strlen(table->name) + 1);
+ }
+
+ ut_memcpy(foreign->referenced_table_name, table->name,
+ ut_strlen(table->name) + 1);
+ foreign->referenced_table_name[ut_strlen(table->name)] = '\0';
+
+ foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
+ }
+
return(TRUE);
}
@@ -600,6 +701,7 @@ dict_table_remove_from_cache(
/*=========================*/
dict_table_t* table) /* in, own: table */
{
+ dict_foreign_t* foreign;
dict_index_t* index;
ulint size;
ulint i;
@@ -610,6 +712,29 @@ dict_table_remove_from_cache(
/* printf("Removing table %s from dictionary cache\n", table->name); */
+ /* Remove the foreign constraints from the cache */
+ foreign = UT_LIST_GET_LAST(table->foreign_list);
+
+ while (foreign != NULL) {
+ ut_a(0 == ut_strcmp(foreign->foreign_table_name, table->name));
+
+ dict_foreign_remove_from_cache(foreign);
+ foreign = UT_LIST_GET_LAST(table->foreign_list);
+ }
+
+ /* Reset table field in referencing constraints */
+
+ foreign = UT_LIST_GET_FIRST(table->referenced_list);
+
+ while (foreign != NULL) {
+ ut_a(0 == ut_strcmp(foreign->referenced_table_name,
+ table->name));
+ foreign->referenced_table = NULL;
+ foreign->referenced_index = NULL;
+
+ foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
+ }
+
/* Remove the indexes from the cache */
index = UT_LIST_GET_LAST(table->indexes);
@@ -856,6 +981,21 @@ dict_index_add_to_cache(
new_index->tree = tree;
}
+ if (!(new_index->type & DICT_UNIVERSAL)) {
+
+ new_index->stat_n_diff_key_vals =
+ mem_heap_alloc(new_index->heap,
+ (1 + dict_index_get_n_unique(new_index))
+ * sizeof(ib_longlong));
+ /* Give some sensible values to stat_n_... in case we do
+ not calculate statistics quickly enough */
+
+ for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
+
+ new_index->stat_n_diff_key_vals[i] = 100;
+ }
+ }
+
/* Add the index to the list of indexes stored in the tree */
UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index);
@@ -1290,6 +1430,654 @@ dict_index_build_internal_non_clust(
return(new_index);
}
+/*====================== FOREIGN KEY PROCESSING ========================*/
+
+/*************************************************************************
+Frees a foreign key struct. */
+static
+void
+dict_foreign_free(
+/*==============*/
+ dict_foreign_t* foreign) /* in, own: foreign key struct */
+{
+ mem_heap_free(foreign->heap);
+}
+
+/**************************************************************************
+Removes a foreign constraint struct from the dictionary cache. */
+static
+void
+dict_foreign_remove_from_cache(
+/*===========================*/
+ dict_foreign_t* foreign) /* in, own: foreign constraint */
+{
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+ ut_a(foreign);
+
+ if (foreign->referenced_table) {
+ UT_LIST_REMOVE(referenced_list,
+ foreign->referenced_table->referenced_list, foreign);
+ }
+
+ if (foreign->foreign_table) {
+ UT_LIST_REMOVE(foreign_list,
+ foreign->foreign_table->foreign_list, foreign);
+ }
+
+ dict_foreign_free(foreign);
+}
+
+/**************************************************************************
+Looks for the foreign constraint from the foreign and referenced lists
+of a table. */
+static
+dict_foreign_t*
+dict_foreign_find(
+/*==============*/
+ /* out: foreign constraint */
+ dict_table_t* table, /* in: table object */
+ char* id) /* in: foreign constraint id */
+{
+ dict_foreign_t* foreign;
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ foreign = UT_LIST_GET_FIRST(table->foreign_list);
+
+ while (foreign) {
+ if (ut_strcmp(id, foreign->id) == 0) {
+
+ return(foreign);
+ }
+
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+
+ foreign = UT_LIST_GET_FIRST(table->referenced_list);
+
+ while (foreign) {
+ if (ut_strcmp(id, foreign->id) == 0) {
+
+ return(foreign);
+ }
+
+ foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
+ }
+
+ return(NULL);
+}
+
+/*************************************************************************
+Tries to find an index whose first fields are the columns in the array,
+in the same order. */
+static
+dict_index_t*
+dict_foreign_find_index(
+/*====================*/
+ /* out: matching index, NULL if not found */
+ dict_table_t* table, /* in: table */
+ char** columns,/* in: array of column names */
+ ulint n_cols, /* in: number of columns */
+ dict_index_t* types_idx)/* in: NULL or an index to whose types the
+ column types must match */
+{
+ dict_index_t* index;
+ char* col_name;
+ ulint i;
+
+ index = dict_table_get_first_index(table);
+
+ while (index != NULL) {
+ if (dict_index_get_n_fields(index) >= n_cols) {
+
+ for (i = 0; i < n_cols; i++) {
+ col_name = dict_index_get_nth_field(index, i)
+ ->col->name;
+ if (ut_strlen(columns[i]) !=
+ ut_strlen(col_name)
+ || 0 != ut_memcmp(columns[i],
+ col_name,
+ ut_strlen(col_name))) {
+ break;
+ }
+
+ if (types_idx && !cmp_types_are_equal(
+ dict_index_get_nth_type(index, i),
+ dict_index_get_nth_type(types_idx, i))) {
+
+ break;
+ }
+ }
+
+ if (i == n_cols) {
+ /* We found a matching index */
+
+ return(index);
+ }
+ }
+
+ index = dict_table_get_next_index(index);
+ }
+
+ return(NULL);
+}
+
+/**************************************************************************
+Adds a foreign key constraint object to the dictionary cache. May free
+the object if there already is an object with the same identifier in.
+At least one of the foreign table and the referenced table must already
+be in the dictionary cache! */
+
+ulint
+dict_foreign_add_to_cache(
+/*======================*/
+ /* out: DB_SUCCESS or error code */
+ dict_foreign_t* foreign) /* in, own: foreign key constraint */
+{
+ dict_table_t* for_table;
+ dict_table_t* ref_table;
+ dict_foreign_t* for_in_cache = NULL;
+ dict_index_t* index;
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ for_table = dict_table_check_if_in_cache_low(
+ foreign->foreign_table_name);
+
+ ref_table = dict_table_check_if_in_cache_low(
+ foreign->referenced_table_name);
+ ut_a(for_table || ref_table);
+
+ if (for_table) {
+ for_in_cache = dict_foreign_find(for_table, foreign->id);
+ }
+
+ if (!for_in_cache && ref_table) {
+ for_in_cache = dict_foreign_find(ref_table, foreign->id);
+ }
+
+ if (for_in_cache) {
+ /* Free the foreign object */
+ mem_heap_free(foreign->heap);
+ } else {
+ for_in_cache = foreign;
+ }
+
+ if (for_in_cache->referenced_table == NULL && ref_table) {
+ index = dict_foreign_find_index(ref_table,
+ for_in_cache->referenced_col_names,
+ for_in_cache->n_fields,
+ for_in_cache->foreign_index);
+
+ if (index == NULL) {
+ if (for_in_cache == foreign) {
+ mem_heap_free(foreign->heap);
+ }
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ for_in_cache->referenced_table = ref_table;
+ for_in_cache->referenced_index = index;
+ UT_LIST_ADD_LAST(referenced_list,
+ ref_table->referenced_list,
+ for_in_cache);
+ }
+
+ if (for_in_cache->foreign_table == NULL && for_table) {
+ index = dict_foreign_find_index(for_table,
+ for_in_cache->foreign_col_names,
+ for_in_cache->n_fields,
+ for_in_cache->referenced_index);
+
+ if (index == NULL) {
+ if (for_in_cache == foreign) {
+ mem_heap_free(foreign->heap);
+ }
+
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ for_in_cache->foreign_table = for_table;
+ for_in_cache->foreign_index = index;
+ UT_LIST_ADD_LAST(foreign_list,
+ for_table->foreign_list,
+ for_in_cache);
+ }
+
+ return(DB_SUCCESS);
+}
+
+/*************************************************************************
+Scans from pointer onwards. Stops if is at the start of a copy of
+'string' where characters are compared without case sensitivity. Stops
+also at '\0'. */
+static
+char*
+dict_scan_to(
+/*=========*/
+
+ char* ptr, /* in: scan from */
+ char* string) /* in: look for this */
+{
+ ibool success;
+ ulint i;
+loop:
+ if (*ptr == '\0') {
+ return(ptr);
+ }
+
+ success = TRUE;
+
+ for (i = 0; i < ut_strlen(string); i++) {
+ if (toupper((ulint)(ptr[i])) != toupper((ulint)(string[i]))) {
+ success = FALSE;
+
+ break;
+ }
+ }
+
+ if (success) {
+
+ return(ptr);
+ }
+
+ ptr++;
+
+ goto loop;
+}
+
+/*************************************************************************
+Accepts a specified string. Comparisons are case-insensitive. */
+static
+char*
+dict_accept(
+/*========*/
+ /* out: if string was accepted, the pointer
+ is moved after that, else ptr is returned */
+ char* ptr, /* in: scan from this */
+ char* string, /* in: accept only this string as the next
+ non-whitespace string */
+ ibool* success)/* out: TRUE if accepted */
+{
+ char* old_ptr = ptr;
+ char* old_ptr2;
+
+ *success = FALSE;
+
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+
+ old_ptr2 = ptr;
+
+ ptr = dict_scan_to(ptr, string);
+
+ if (*ptr == '\0' || old_ptr2 != ptr) {
+ return(old_ptr);
+ }
+
+ *success = TRUE;
+
+ return(ptr + ut_strlen(string));
+}
+
+/*************************************************************************
+Tries to scan a column name. */
+static
+char*
+dict_scan_col(
+/*==========*/
+ /* out: scanned to */
+ char* ptr, /* in: scanned to */
+ ibool* success,/* out: TRUE if success */
+ dict_table_t* table, /* in: table in which the column is */
+ dict_col_t** column, /* out: pointer to column if success */
+ char** column_name)/* out: pointer to column->name if
+ success */
+{
+ dict_col_t* col;
+ char* old_ptr;
+ ulint i;
+
+ *success = FALSE;
+
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+
+ if (*ptr == '\0') {
+
+ return(ptr);
+ }
+
+ old_ptr = ptr;
+
+ while (!isspace(*ptr) && *ptr != ',' && *ptr != ')') {
+ ptr++;
+ }
+
+ for (i = 0; i < dict_table_get_n_cols(table); i++) {
+
+ col = dict_table_get_nth_col(table, i);
+
+ if (ut_strlen(col->name) == (ulint)(ptr - old_ptr)
+ && 0 == ut_memcmp(col->name, old_ptr,
+ (ulint)(ptr - old_ptr))) {
+
+ /* Found */
+
+ *success = TRUE;
+ *column = col;
+ *column_name = col->name;
+
+ break;
+ }
+ }
+
+ return(ptr);
+}
+
+/*************************************************************************
+Scans the referenced table name from an SQL string. */
+static
+char*
+dict_scan_table_name(
+/*=================*/
+ /* out: scanned to */
+ char* ptr, /* in: scanned to */
+ dict_table_t** table, /* out: table object or NULL if error */
+ char* name) /* in: foreign key table name */
+{
+ char* dot_ptr = NULL;
+ char* old_ptr;
+ ulint i;
+ char second_table_name[10000];
+
+ *table = NULL;
+
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+
+ if (*ptr == '\0') {
+
+ return(ptr);
+ }
+
+ old_ptr = ptr;
+
+ while (!isspace(*ptr) && *ptr != '(') {
+ if (*ptr == '.') {
+ dot_ptr = ptr;
+ }
+
+ ptr++;
+ }
+
+ if (ptr - old_ptr > 9000) {
+ return(old_ptr);
+ }
+
+ if (dot_ptr == NULL) {
+ /* Copy the database name from 'name' to the start */
+ for (i = 0;; i++) {
+ second_table_name[i] = name[i];
+ if (name[i] == '/') {
+ i++;
+ break;
+ }
+ }
+
+ ut_memcpy(second_table_name + i, old_ptr, ptr - old_ptr);
+ second_table_name[i + (ptr - old_ptr)] = '\0';
+ } else {
+ ut_memcpy(second_table_name, old_ptr, ptr - old_ptr);
+ second_table_name[dot_ptr - old_ptr] = '/';
+ second_table_name[ptr - old_ptr] = '\0';
+ }
+
+ *table = dict_table_get_low(second_table_name);
+
+ return(ptr);
+}
+
+/*************************************************************************
+Returns the number of opening brackets '(' subtracted by the number
+of closing brackets ')' between string and ptr. */
+static
+int
+dict_bracket_count(
+/*===============*/
+ /* out: bracket count */
+ char* string, /* in: start of string */
+ char* ptr) /* in: end of string */
+{
+ int count = 0;
+
+ while (string != ptr) {
+ if (*string == '(') {
+ count++;
+ }
+ if (*string == ')') {
+ count--;
+ }
+
+ string++;
+ }
+
+ return(count);
+}
+
+/*************************************************************************
+Scans a table create SQL string and adds to the data dictionary the foreign
+key constraints declared in the string. This function should be called after
+the indexes for a table have been created. Each foreign key constraint must
+be accompanied with indexes in both participating tables. The indexes are
+allowed to contain more fields than mentioned in the constraint. */
+
+ulint
+dict_create_foreign_constraints(
+/*============================*/
+ /* out: error code or DB_SUCCESS */
+ trx_t* trx, /* in: transaction */
+ char* sql_string, /* in: table create statement where
+ foreign keys are declared like:
+ FOREIGN KEY (a, b) REFERENCES table2(c, d),
+ table2 can be written also with the database
+ name before it: test.table2; the default
+ database id the database of parameter name */
+ char* name) /* in: table full name in the normalized form
+ database_name/table_name */
+{
+ dict_table_t* table;
+ dict_table_t* referenced_table;
+ dict_index_t* index;
+ dict_foreign_t* foreign;
+ char* ptr = sql_string;
+ ibool success;
+ ulint error;
+ ulint i;
+ dict_col_t* columns[1000];
+ char* column_names[1000];
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ table = dict_table_get_low(name);
+
+ if (table == NULL) {
+ return(DB_ERROR);
+ }
+loop:
+ ptr = dict_scan_to(ptr, "FOREIGN");
+
+ if (*ptr == '\0' || dict_bracket_count(sql_string, ptr) != 1) {
+
+ /* The following call adds the foreign key constraints
+ to the data dictionary system tables on disk */
+
+ error = dict_create_add_foreigns_to_dictionary(table, trx);
+
+ return(error);
+ }
+
+ ptr = dict_accept(ptr, "FOREIGN", &success);
+
+ if (!isspace(*ptr)) {
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ ptr = dict_accept(ptr, "KEY", &success);
+
+ if (!success) {
+ goto loop;
+ }
+
+ ptr = dict_accept(ptr, "(", &success);
+
+ if (!success) {
+ goto loop;
+ }
+
+ i = 0;
+
+ /* Scan the columns in the first list */
+col_loop1:
+ ptr = dict_scan_col(ptr, &success, table, columns + i,
+ column_names + i);
+ if (!success) {
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ i++;
+
+ ptr = dict_accept(ptr, ",", &success);
+
+ if (success) {
+ goto col_loop1;
+ }
+
+ ptr = dict_accept(ptr, ")", &success);
+
+ if (!success) {
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ /* Try to find an index which contains the columns
+ as the first fields and in the right order */
+
+ index = dict_foreign_find_index(table, column_names, i, NULL);
+
+ if (!index) {
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ ptr = dict_accept(ptr, "REFERENCES", &success);
+
+ if (!success || !isspace(*ptr)) {
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ /* Let us create a constraint struct */
+
+ foreign = dict_mem_foreign_create();
+
+ foreign->foreign_table = table;
+ foreign->foreign_table_name = table->name;
+ foreign->foreign_index = index;
+ foreign->n_fields = i;
+ foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
+ i * sizeof(void*));
+ for (i = 0; i < foreign->n_fields; i++) {
+ foreign->foreign_col_names[i] = mem_heap_alloc(foreign->heap,
+ 1 + ut_strlen(columns[i]->name));
+ ut_memcpy(foreign->foreign_col_names[i], columns[i]->name,
+ 1 + ut_strlen(columns[i]->name));
+ }
+
+ ptr = dict_scan_table_name(ptr, &referenced_table, name);
+
+ if (!referenced_table) {
+ dict_foreign_free(foreign);
+
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ ptr = dict_accept(ptr, "(", &success);
+
+ if (!success) {
+ dict_foreign_free(foreign);
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ /* Scan the columns in the second list */
+ i = 0;
+
+col_loop2:
+ ptr = dict_scan_col(ptr, &success, referenced_table, columns + i,
+ column_names + i);
+ i++;
+
+ if (!success) {
+ dict_foreign_free(foreign);
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ ptr = dict_accept(ptr, ",", &success);
+
+ if (success) {
+ goto col_loop2;
+ }
+
+ ptr = dict_accept(ptr, ")", &success);
+
+ if (!success || foreign->n_fields != i) {
+ dict_foreign_free(foreign);
+
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ /* Try to find an index which contains the columns as the first fields
+ and in the right order, and the types are the same as in
+ foreign->foreign_index */
+
+ index = dict_foreign_find_index(referenced_table, column_names, i,
+ foreign->foreign_index);
+
+ if (!index) {
+ dict_foreign_free(foreign);
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ foreign->referenced_index = index;
+ foreign->referenced_table = referenced_table;
+
+ foreign->referenced_table_name = mem_heap_alloc(foreign->heap,
+ 1 + ut_strlen(referenced_table->name));
+
+ ut_memcpy(foreign->referenced_table_name, referenced_table->name,
+ 1 + ut_strlen(referenced_table->name));
+
+ foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
+ i * sizeof(void*));
+ for (i = 0; i < foreign->n_fields; i++) {
+ foreign->referenced_col_names[i]
+ = mem_heap_alloc(foreign->heap,
+ 1 + ut_strlen(columns[i]->name));
+ ut_memcpy(
+ foreign->referenced_col_names[i], columns[i]->name,
+ 1 + ut_strlen(columns[i]->name));
+ }
+
+ /* We found an ok constraint definition: add to the lists */
+
+ UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
+ UT_LIST_ADD_LAST(referenced_list, referenced_table->referenced_list,
+ foreign);
+ goto loop;
+}
+
+/*==================== END OF FOREIGN KEY PROCESSING ====================*/
+
/**************************************************************************
Adds a stored procedure object to the dictionary cache. */
@@ -1733,77 +2521,127 @@ dict_tree_build_data_tuple(
}
/*************************************************************************
-Calculates new estimates for table and index statistics. The statistics
-are used in query optimization. */
+Calculates the minimum record length in an index. */
-void
-dict_update_statistics(
-/*===================*/
- dict_table_t* table) /* in: table */
+ulint
+dict_index_calc_min_rec_len(
+/*========================*/
+ dict_index_t* index) /* in: index */
{
- 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);
+ ulint sum = 0;
+ ulint i;
- n_rows = btr_estimate_n_rows_in_range(index, start, PAGE_CUR_G,
- end, PAGE_CUR_L);
- mem_heap_free(heap);
+ for (i = 0; i < dict_index_get_n_fields(index); i++) {
+ sum += dtype_get_fixed_size(dict_index_get_nth_type(index, i));
+ }
- if (n_rows > 0) {
- /* For small tables our estimate function tends to give
- values 1 too big */
- n_rows--;
+ if (sum > 127) {
+ sum += 2 * dict_index_get_n_fields(index);
+ } else {
+ sum += dict_index_get_n_fields(index);
}
- mutex_enter(&(dict_sys->mutex));
+ sum += REC_N_EXTRA_BYTES;
- table->stat_last_estimate_counter = table->stat_modif_counter;
- table->stat_n_rows = n_rows;
+ return(sum);
+}
- mutex_exit(&(dict_sys->mutex));
+/*************************************************************************
+Calculates new estimates for table and index statistics. The statistics
+are used in query optimization. */
+
+void
+dict_update_statistics_low(
+/*=======================*/
+ dict_table_t* table, /* in: table */
+ ibool has_dict_mutex) /* in: TRUE if the caller has the
+ dictionary mutex */
+{
+ dict_index_t* index;
+ ulint size;
+ ulint sum_of_index_sizes = 0;
/* Find out the sizes of the indexes and how many different values
for the key they approximately have */
-
+
+ index = dict_table_get_first_index(table);
+
while (index) {
- n_vals = btr_estimate_number_of_different_key_vals(index);
size = btr_get_size(index, BTR_TOTAL_SIZE);
+ index->stat_index_size = size;
+
sum_of_index_sizes += size;
- mutex_enter(&(dict_sys->mutex));
+ size = btr_get_size(index, BTR_N_LEAF_PAGES);
- index->stat_n_diff_key_vals = n_vals;
- index->stat_index_size = size;
+ if (size == 0) {
+ /* The root node of the tree is a leaf */
+ size = 1;
+ }
- mutex_exit(&(dict_sys->mutex));
+ index->stat_n_leaf_pages = size;
+
+ btr_estimate_number_of_different_key_vals(index);
index = dict_table_get_next_index(index);
}
index = dict_table_get_first_index(table);
+ table->stat_n_rows = index->stat_n_diff_key_vals[
+ dict_index_get_n_unique(index)];
+
table->stat_clustered_index_size = index->stat_index_size;
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
- - index->stat_index_size;
+ - index->stat_index_size;
table->stat_last_estimate_counter = table->stat_modif_counter;
}
+/*************************************************************************
+Calculates new estimates for table and index statistics. The statistics
+are used in query optimization. */
+
+void
+dict_update_statistics(
+/*===================*/
+ dict_table_t* table) /* in: table */
+{
+ dict_update_statistics_low(table, FALSE);
+}
+
+/**************************************************************************
+Prints info of a foreign key constraint. */
+static
+void
+dict_foreign_print_low(
+/*===================*/
+ dict_foreign_t* foreign) /* in: foreign key constraint */
+{
+ ulint i;
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ printf(" FOREIGN KEY CONSTRAINT %s: %s (", foreign->id,
+ foreign->foreign_table_name);
+
+ for (i = 0; i < foreign->n_fields; i++) {
+ printf(" %s", foreign->foreign_col_names[i]);
+ }
+
+ printf(" )\n");
+
+ printf(" REFERENCES %s (", foreign->referenced_table_name);
+
+ for (i = 0; i < foreign->n_fields; i++) {
+ printf(" %s", foreign->referenced_col_names[i]);
+ }
+
+ printf(" )\n");
+}
+
/**************************************************************************
Prints a table data. */
@@ -1839,31 +2677,57 @@ dict_table_print_by_name(
/**************************************************************************
Prints a table data. */
-static
+
void
dict_table_print_low(
/*=================*/
dict_table_t* table) /* in: table */
{
- ulint i;
dict_index_t* index;
+ dict_foreign_t* foreign;
+ ulint i;
ut_ad(mutex_own(&(dict_sys->mutex)));
+ dict_update_statistics_low(table, TRUE);
+
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(" ");
+ printf(
+ "TABLE: name %s, id %lu %lu, columns %lu, indexes %lu, appr.rows %lu\n",
+ table->name,
+ ut_dulint_get_high(table->id),
+ ut_dulint_get_low(table->id),
+ table->n_cols, UT_LIST_GET_LEN(table->indexes),
+ (ulint)table->stat_n_rows);
+ printf(" COLUMNS: ");
+
+ for (i = 0; i < table->n_cols - 1; i++) {
dict_col_print_low(dict_table_get_nth_col(table, i));
+ printf("; ");
}
+ printf("\n");
+
index = UT_LIST_GET_FIRST(table->indexes);
while (index != NULL) {
dict_index_print_low(index);
index = UT_LIST_GET_NEXT(indexes, index);
}
+
+ foreign = UT_LIST_GET_FIRST(table->foreign_list);
+
+ while (foreign != NULL) {
+ dict_foreign_print_low(foreign);
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+
+ foreign = UT_LIST_GET_FIRST(table->referenced_list);
+
+ while (foreign != NULL) {
+ dict_foreign_print_low(foreign);
+ foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
+ }
}
/**************************************************************************
@@ -1879,7 +2743,7 @@ dict_col_print_low(
ut_ad(mutex_own(&(dict_sys->mutex)));
type = dict_col_get_type(col);
- printf("COLUMN: name %s; ", col->name);
+ printf("%s: ", col->name);
dtype_print(type);
}
@@ -1892,28 +2756,47 @@ dict_index_print_low(
/*=================*/
dict_index_t* index) /* in: index */
{
- ulint i;
dict_tree_t* tree;
+ ib_longlong n_vals;
+ ulint i;
ut_ad(mutex_own(&(dict_sys->mutex)));
tree = index->tree;
-
+
+ if (index->n_user_defined_cols > 0) {
+ n_vals = index->stat_n_diff_key_vals[
+ index->n_user_defined_cols];
+ } else {
+ n_vals = index->stat_n_diff_key_vals[1];
+ }
+
+
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);
+ " INDEX: name %s, table name %s, id %lu %lu, fields %lu/%lu, type %lu\n",
+ index->name, index->table_name,
+ ut_dulint_get_high(tree->id),
+ ut_dulint_get_low(tree->id),
+ index->n_user_defined_cols,
+ index->n_fields, index->type);
+ printf(
+ " root page %lu, appr.key vals %lu, leaf pages %lu, size pages %lu\n",
+ tree->page,
+ (ulint)n_vals,
+ index->stat_n_leaf_pages,
+ index->stat_index_size);
+ printf(" FIELDS: ");
+
for (i = 0; i < index->n_fields; i++) {
- printf(" ");
dict_field_print_low(dict_index_get_nth_field(index, i));
}
- btr_print_size(tree);
+ printf("\n");
+
+/* btr_print_size(tree); */
- btr_print_tree(tree, 7);
+/* btr_print_tree(tree, 7); */
}
/**************************************************************************
@@ -1926,6 +2809,5 @@ dict_field_print_low(
{
ut_ad(mutex_own(&(dict_sys->mutex)));
- printf("FIELD: column name %s, order criterion %lu\n", field->name,
- field->order);
+ printf(" %s", field->name);
}
diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c
index be16988086a..dcdc9ee01cd 100644
--- a/innobase/dict/dict0load.c
+++ b/innobase/dict/dict0load.c
@@ -48,8 +48,171 @@ dict_load_fields(
/************************************************************************
+Finds the first table name in the given database. */
+
+char*
+dict_get_first_table_name_in_db(
+/*============================*/
+ /* out, own: table name, NULL if does not exist;
+ the caller must free the memory in the string! */
+ char* name) /* in: database name which ends to '/' */
+{
+ dict_table_t* sys_tables;
+ btr_pcur_t pcur;
+ dict_index_t* sys_index;
+ dtuple_t* tuple;
+ mem_heap_t* heap;
+ dfield_t* dfield;
+ rec_t* rec;
+ byte* field;
+ ulint len;
+ char* table_name;
+ mtr_t mtr;
+
+ 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);
+loop:
+ rec = btr_pcur_get_rec(&pcur);
+
+ if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
+ /* Not found */
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ mem_heap_free(heap);
+
+ return(NULL);
+ }
+
+ field = rec_get_nth_field(rec, 0, &len);
+
+ if (len < strlen(name)
+ || ut_memcmp(name, field, strlen(name)) != 0) {
+ /* Not found */
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ mem_heap_free(heap);
+
+ return(NULL);
+ }
+
+ if (!rec_get_deleted_flag(rec)) {
+
+ /* We found one */
+
+ table_name = mem_alloc(len + 1);
+ ut_memcpy(table_name, field, len);
+ table_name[len] = '\0';
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ mem_heap_free(heap);
+
+ return(table_name);
+ }
+
+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+
+ goto loop;
+}
+
+/************************************************************************
+Prints to the standard output information on all tables found in the data
+dictionary system table. */
+
+void
+dict_print(void)
+/*============*/
+{
+ dict_table_t* sys_tables;
+ dict_index_t* sys_index;
+ dict_table_t* table;
+ btr_pcur_t pcur;
+ rec_t* rec;
+ byte* field;
+ ulint len;
+ char table_name[10000];
+ mtr_t mtr;
+
+ mutex_enter(&(dict_sys->mutex));
+
+ mtr_start(&mtr);
+
+ sys_tables = dict_table_get_low("SYS_TABLES");
+ sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
+
+ btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
+ TRUE, &mtr);
+loop:
+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+
+ rec = btr_pcur_get_rec(&pcur);
+
+ if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
+ /* end of index */
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+
+ mutex_exit(&(dict_sys->mutex));
+
+ return;
+ }
+
+ field = rec_get_nth_field(rec, 0, &len);
+
+ if (!rec_get_deleted_flag(rec)) {
+
+ /* We found one */
+
+ ut_memcpy(table_name, field, len);
+ table_name[len] = '\0';
+
+ btr_pcur_store_position(&pcur, &mtr);
+
+ mtr_commit(&mtr);
+
+ table = dict_table_get_low(table_name);
+
+ if (table == NULL) {
+ fprintf(stderr, "InnoDB: Failed to load table %s\n",
+ table_name);
+ } else {
+ dict_update_statistics_low(table, TRUE);
+
+ dict_table_print_low(table);
+ }
+
+ mtr_start(&mtr);
+
+ btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
+ }
+
+ goto loop;
+}
+
+/************************************************************************
Loads a table definition and also all its index definitions, and also
-the cluster definition if the table is a member in a cluster. */
+the cluster definition if the table is a member in a cluster. Also loads
+all foreign key constraints where the foreign key is in the table or where
+a foreign key references columns in this table. Adds all these to the data
+dictionary cache. */
dict_table_t*
dict_load_table(
@@ -59,7 +222,6 @@ dict_load_table(
{
dict_table_t* table;
dict_table_t* sys_tables;
- mtr_t mtr;
btr_pcur_t pcur;
dict_index_t* sys_index;
dtuple_t* tuple;
@@ -71,6 +233,7 @@ dict_load_table(
char* buf;
ulint space;
ulint n_cols;
+ mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -178,6 +341,106 @@ dict_load_table(
dict_load_indexes(table, heap);
+ ut_a(DB_SUCCESS == dict_load_foreigns(table->name));
+
+ mem_heap_free(heap);
+
+ return(table);
+}
+
+/***************************************************************************
+Loads a table object based on the table id. */
+
+dict_table_t*
+dict_load_table_on_id(
+/*==================*/
+ /* out: table; NULL if table does not exist */
+ dulint table_id) /* in: table id */
+{
+ byte id_buf[8];
+ btr_pcur_t pcur;
+ mem_heap_t* heap;
+ dtuple_t* tuple;
+ dfield_t* dfield;
+ dict_index_t* sys_table_ids;
+ dict_table_t* sys_tables;
+ rec_t* rec;
+ byte* field;
+ ulint len;
+ dict_table_t* table;
+ char* name;
+ mtr_t mtr;
+
+ 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);
@@ -305,7 +568,8 @@ dict_load_columns(
}
/************************************************************************
-Loads definitions for table indexes. */
+Loads definitions for table indexes. Adds them to the data dictionary cache.
+*/
static
void
dict_load_indexes(
@@ -446,7 +710,6 @@ dict_load_fields(
{
dict_table_t* sys_fields;
dict_index_t* sys_index;
- mtr_t mtr;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
@@ -456,6 +719,7 @@ dict_load_fields(
ulint len;
byte* buf;
ulint i;
+ mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -512,100 +776,328 @@ dict_load_fields(
mtr_commit(&mtr);
}
+/************************************************************************
+Loads foreign key constraint col names (also for the referenced table). */
+static
+void
+dict_load_foreign_cols(
+/*===================*/
+ char* id, /* in: foreign constraint id as a null-
+ terminated string */
+ dict_foreign_t* foreign)/* in: foreign constraint object */
+{
+ dict_table_t* sys_foreign_cols;
+ dict_index_t* sys_index;
+ btr_pcur_t pcur;
+ dtuple_t* tuple;
+ dfield_t* dfield;
+ char* col_name;
+ rec_t* rec;
+ byte* field;
+ ulint len;
+ ulint i;
+ mtr_t mtr;
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
+ foreign->n_fields * sizeof(void*));
+
+ foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
+ foreign->n_fields * sizeof(void*));
+ mtr_start(&mtr);
+
+ sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
+ sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
+
+ tuple = dtuple_create(foreign->heap, 1);
+ dfield = dtuple_get_nth_field(tuple, 0);
+
+ dfield_set_data(dfield, id, ut_strlen(id));
+ dict_index_copy_types(tuple, sys_index, 1);
+
+ btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
+ BTR_SEARCH_LEAF, &pcur, &mtr);
+ for (i = 0; i < foreign->n_fields; i++) {
+
+ rec = btr_pcur_get_rec(&pcur);
+
+ ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
+ ut_a(!rec_get_deleted_flag(rec));
+
+ field = rec_get_nth_field(rec, 0, &len);
+ ut_a(len == ut_strlen(id));
+ ut_a(ut_memcmp(id, field, len) == 0);
+
+ field = rec_get_nth_field(rec, 1, &len);
+ ut_a(len == 4);
+ ut_a(i == mach_read_from_4(field));
+
+ field = rec_get_nth_field(rec, 4, &len);
+
+ col_name = mem_heap_alloc(foreign->heap, len + 1);
+ ut_memcpy(col_name, field, len);
+ col_name[len] = '\0';
+
+ foreign->foreign_col_names[i] = col_name;
+
+ field = rec_get_nth_field(rec, 5, &len);
+
+ col_name = mem_heap_alloc(foreign->heap, len + 1);
+ ut_memcpy(col_name, field, len);
+ col_name[len] = '\0';
+
+ foreign->referenced_col_names[i] = col_name;
+
+ 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. */
+Loads a foreign key constraint to the dictionary cache. */
+static
+ulint
+dict_load_foreign(
+/*==============*/
+ /* out: DB_SUCCESS or error code */
+ char* id) /* in: foreign constraint id as a null-terminated
+ string */
+{
+ dict_foreign_t* foreign;
+ dict_table_t* sys_foreign;
+ btr_pcur_t pcur;
+ dict_index_t* sys_index;
+ dtuple_t* tuple;
+ mem_heap_t* heap2;
+ dfield_t* dfield;
+ rec_t* rec;
+ byte* field;
+ ulint len;
+ ulint err;
+ mtr_t mtr;
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
-dict_table_t*
-dict_load_table_on_id(
-/*==================*/
- /* out: table; NULL if table does not exist */
- dulint table_id) /* in: table id */
+ heap2 = mem_heap_create(1000);
+
+ mtr_start(&mtr);
+
+ sys_foreign = dict_table_get_low("SYS_FOREIGN");
+ sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
+
+ tuple = dtuple_create(heap2, 1);
+ dfield = dtuple_get_nth_field(tuple, 0);
+
+ dfield_set_data(dfield, id, ut_strlen(id));
+ dict_index_copy_types(tuple, sys_index, 1);
+
+ btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
+ BTR_SEARCH_LEAF, &pcur, &mtr);
+ rec = btr_pcur_get_rec(&pcur);
+
+ if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
+ || rec_get_deleted_flag(rec)) {
+ /* Not found */
+
+ fprintf(stderr,
+ "InnoDB: Error A: cannot load foreign constraint %s\n", id);
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ mem_heap_free(heap2);
+
+ return(DB_ERROR);
+ }
+
+ field = rec_get_nth_field(rec, 0, &len);
+
+ /* Check if the id in record is the searched one */
+ if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
+
+ fprintf(stderr,
+ "InnoDB: Error B: cannot load foreign constraint %s\n", id);
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ mem_heap_free(heap2);
+
+ return(DB_ERROR);
+ }
+
+ /* Read the table names and the number of columns associated
+ with the constraint */
+
+ mem_heap_free(heap2);
+
+ foreign = dict_mem_foreign_create();
+
+ foreign->n_fields = mach_read_from_4(rec_get_nth_field(rec, 5, &len));
+
+ ut_a(len == 4);
+
+ foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(id) + 1);
+
+ ut_memcpy(foreign->id, id, ut_strlen(id) + 1);
+
+ field = rec_get_nth_field(rec, 3, &len);
+
+ foreign->foreign_table_name = mem_heap_alloc(foreign->heap, 1 + len);
+
+ ut_memcpy(foreign->foreign_table_name, field, len);
+ foreign->foreign_table_name[len] = '\0';
+
+ field = rec_get_nth_field(rec, 4, &len);
+
+ foreign->referenced_table_name = mem_heap_alloc(foreign->heap, 1 + len);
+
+ ut_memcpy(foreign->referenced_table_name, field, len);
+ foreign->referenced_table_name[len] = '\0';
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+
+ dict_load_foreign_cols(id, foreign);
+
+ /* Note that there may already be a foreign constraint object in
+ the dictionary cache for this constraint: then the following
+ call only sets the pointers in it to point to the appropriate table
+ and index objects and frees the newly created object foreign. */
+
+ err = dict_foreign_add_to_cache(foreign);
+
+ return(err);
+}
+
+/***************************************************************************
+Loads foreign key constraints where the table is either the foreign key
+holder or where the table is referenced by a foreign key. Adds these
+constraints to the data dictionary. Note that we know that the dictionary
+cache already contains all constraints where the other relevant table is
+already in the dictionary cache. */
+
+ulint
+dict_load_foreigns(
+/*===============*/
+ /* out: DB_SUCCESS or error code */
+ char* table_name) /* in: table name */
{
- 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;
+ dict_index_t* sec_index;
+ dict_table_t* sys_foreign;
rec_t* rec;
byte* field;
ulint len;
- dict_table_t* table;
- char* name;
+ char* id ;
+ ulint err;
+ mtr_t mtr;
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. */
+ sys_foreign = dict_table_get_low("SYS_FOREIGN");
+
+ if (sys_foreign == NULL) {
+ /* No foreign keys defined yet in this database */
+
+ fprintf(stderr,
+ "InnoDB: Error: no foreign key system tables in the database\n");
+
+ return(DB_ERROR);
+ }
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));
+
+ /* Get the secondary index based on FOR_NAME from table
+ SYS_FOREIGN */
+
+ sec_index = dict_table_get_next_index(
+ dict_table_get_first_index(sys_foreign));
+start_load:
heap = mem_heap_create(256);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
- /* 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);
+ dfield_set_data(dfield, table_name, ut_strlen(table_name));
+ dict_index_copy_types(tuple, sec_index, 1);
- btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
+ btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
+loop:
rec = btr_pcur_get_rec(&pcur);
- if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
- || rec_get_deleted_flag(rec)) {
- /* Not found */
+ if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
+ /* End of index */
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
- mem_heap_free(heap);
-
- return(NULL);
+ goto load_next_index;
}
- /*---------------------------------------------------*/
- /* Now we have the record in the secondary index containing the
- table ID and NAME */
+ /* Now we have the record in the secondary index containing a table
+ name and a foreign constraint ID */
rec = btr_pcur_get_rec(&pcur);
field = rec_get_nth_field(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) {
+ /* Check if the table name in record is the one searched for */
+ if (len != ut_strlen(table_name)
+ || 0 != ut_memcmp(field, table_name, len)) {
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
- mem_heap_free(heap);
-
- return(NULL);
+ goto load_next_index;
}
- /* Now we get the table name from the record */
+ if (rec_get_deleted_flag(rec)) {
+
+ goto next_rec;
+ }
+
+ /* Now we get a foreign key constraint id */
field = rec_get_nth_field(rec, 1, &len);
- name = mem_heap_alloc(heap, len + 1);
- ut_memcpy(name, field, len);
- name[len] = '\0';
+ id = mem_heap_alloc(heap, len + 1);
+ ut_memcpy(id, field, len);
+ id[len] = '\0';
- /* Load the table definition to memory */
- table = dict_load_table(name);
+ btr_pcur_store_position(&pcur, &mtr);
- ut_a(table);
+ mtr_commit(&mtr);
+
+ /* Load the foreign constraint definition to the dictionary cache */
+ err = dict_load_foreign(id);
+
+ if (err != DB_SUCCESS) {
+ btr_pcur_close(&pcur);
+ mem_heap_free(heap);
+
+ return(err);
+ }
+
+ mtr_start(&mtr);
+
+ btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
+next_rec:
+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+
+ goto loop;
+
+load_next_index:
btr_pcur_close(&pcur);
mtr_commit(&mtr);
mem_heap_free(heap);
+
+ sec_index = dict_table_get_next_index(sec_index);
- return(table);
+ if (sec_index != NULL) {
+
+ mtr_start(&mtr);
+
+ goto start_load;
+ }
+
+ return(DB_SUCCESS);
}
diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c
index 6947db11aea..57926ab9d2f 100644
--- a/innobase/dict/dict0mem.c
+++ b/innobase/dict/dict0mem.c
@@ -18,6 +18,7 @@ Created 1/8/1996 Heikki Tuuri
#include "dict0dict.h"
#include "que0que.h"
#include "pars0pars.h"
+#include "lock0lock.h"
#define DICT_HEAP_SIZE 100 /* initial memory heap size when
creating a table or index object */
@@ -63,7 +64,12 @@ dict_mem_table_create(
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
* sizeof(dict_col_t));
UT_LIST_INIT(table->indexes);
+
+ table->auto_inc_lock = mem_heap_alloc(heap, lock_get_size());
+
UT_LIST_INIT(table->locks);
+ UT_LIST_INIT(table->foreign_list);
+ UT_LIST_INIT(table->referenced_list);
table->does_not_fit_in_memory = FALSE;
@@ -199,6 +205,8 @@ dict_mem_index_create(
* sizeof(dict_field_t));
/* The '1 +' above prevents allocation
of an empty mem block */
+ index->stat_n_diff_key_vals = NULL;
+
index->cached = FALSE;
index->magic_n = DICT_INDEX_MAGIC_N;
@@ -206,6 +214,41 @@ dict_mem_index_create(
}
/**************************************************************************
+Creates and initializes a foreign constraint memory object. */
+
+dict_foreign_t*
+dict_mem_foreign_create(void)
+/*=========================*/
+ /* out, own: foreign constraint struct */
+{
+ dict_foreign_t* foreign;
+ mem_heap_t* heap;
+
+ heap = mem_heap_create(100);
+
+ foreign = mem_heap_alloc(heap, sizeof(dict_foreign_t));
+
+ foreign->heap = heap;
+
+ foreign->id = NULL;
+
+ foreign->foreign_table_name = NULL;
+ foreign->foreign_table = NULL;
+ foreign->foreign_col_names = NULL;
+
+ foreign->referenced_table_name = NULL;
+ foreign->referenced_table = NULL;
+ foreign->referenced_col_names = NULL;
+
+ foreign->n_fields = 0;
+
+ foreign->foreign_index = NULL;
+ foreign->referenced_index = NULL;
+
+ return(foreign);
+}
+
+/**************************************************************************
Adds a field definition to an index. NOTE: does not take a copy
of the column name if the field is a column. The memory occupied
by the column name may be released only after publishing the index. */