diff options
author | Aleksey Midenkov <midenok@gmail.com> | 2021-03-23 02:10:05 +0300 |
---|---|---|
committer | Aleksey Midenkov <midenok@gmail.com> | 2021-03-23 14:38:24 +0300 |
commit | 3c342906adc37f76d01ab7bb6b93075a61c43494 (patch) | |
tree | 53cec6dba9ee8b77be029179b0e15032c2191aa7 | |
parent | 0a91c5ad3adc0e9d731741d8e799e58c62da2134 (diff) | |
download | mariadb-git-bb-10.6-midenok-MDEV-12483-partitioning.tar.gz |
create_table_info_t::create_foreign_keys()bb-10.6-midenok-MDEV-12483-partitioning
-rw-r--r-- | mysql-test/main/partition.result | 2 | ||||
-rw-r--r-- | mysql-test/main/partition.test | 2 | ||||
-rw-r--r-- | storage/innobase/dict/dict0dict.cc | 35 | ||||
-rw-r--r-- | storage/innobase/dict/dict0mem.cc | 29 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 229 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.h | 31 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 12 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.h | 31 |
8 files changed, 208 insertions, 163 deletions
diff --git a/mysql-test/main/partition.result b/mysql-test/main/partition.result index d4f5ff888e7..3123dace457 100644 --- a/mysql-test/main/partition.result +++ b/mysql-test/main/partition.result @@ -306,7 +306,7 @@ drop table t1; CREATE TABLE t1 (a INT, FOREIGN KEY (a) REFERENCES t0 (a)) ENGINE=MyISAM PARTITION BY HASH (a); -ERROR HY000: Partitioned tables do not support FOREIGN KEY +ERROR 42S02: Table 'test.t0' doesn't exist CREATE TABLE t1 ( pk INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (pk) diff --git a/mysql-test/main/partition.test b/mysql-test/main/partition.test index 451fdb6b204..a78f5c73c9b 100644 --- a/mysql-test/main/partition.test +++ b/mysql-test/main/partition.test @@ -290,7 +290,7 @@ drop table t1; # # Bug#36001: Partitions: spelling and using some error messages # ---error ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING +--error ER_NO_SUCH_TABLE CREATE TABLE t1 (a INT, FOREIGN KEY (a) REFERENCES t0 (a)) ENGINE=MyISAM PARTITION BY HASH (a); diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index da18b71c9a2..c4bcae5841e 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1908,23 +1908,26 @@ dict_table_rename_in_cache( foreign = *it; - if (strlen(foreign->referenced_table_name()) - < strlen(table->name.m_name)) { - /* Allocate a longer name buffer; - TODO: store buf len to save memory */ - - foreign->ref_info[0].referenced_table_name = mem_heap_strdup( - foreign->heap, table->name.m_name); - - dict_mem_referenced_table_name_lookup_set( - foreign, TRUE); - } else { - /* Use the same buffer */ - strcpy(foreign->referenced_table_name(), - table->name.m_name); + for (foreign_ref_info& ref_info: foreign->ref_info) { + if (strlen(ref_info.referenced_table_name) + < strlen(table->name.m_name)) { + /* Allocate a longer name buffer; + TODO: store buf len to save memory */ + + // FIXME: test + ref_info.referenced_table_name = mem_heap_strdup( + foreign->heap, table->name.m_name); + + dict_mem_referenced_table_name_lookup_set( + ref_info, foreign->heap); + } else { + /* Use the same buffer */ + strcpy(ref_info.referenced_table_name, + table->name.m_name); - dict_mem_referenced_table_name_lookup_set( - foreign, FALSE); + dict_mem_referenced_table_name_lookup_set( + ref_info, NULL); + } } } diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 395bb632be5..3eb19ae6139 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -801,7 +801,7 @@ dict_mem_index_create( Creates and initializes a foreign constraint memory object. @return own: foreign constraint struct */ dict_foreign_t* -dict_mem_foreign_create(void) +dict_mem_foreign_create(bool add_refinfo) /*=========================*/ { dict_foreign_t* foreign; @@ -816,7 +816,8 @@ dict_mem_foreign_create(void) foreign->heap = heap; foreign->v_cols = NULL; - foreign->ref_info.resize(1); // FIXME: free + if (add_refinfo) + foreign->ref_info.resize(1); // FIXME: free DBUG_PRINT("dict_mem_foreign_create", ("heap: %p", heap)); @@ -859,27 +860,25 @@ lower_case_table_names. If that is 0 or 1, referenced_table_name_lookup will point to referenced_table_name. If 2, then another string is allocated from foreign->heap and set to lower case. */ void -dict_mem_referenced_table_name_lookup_set( -/*======================================*/ - dict_foreign_t* foreign, /*!< in/out: foreign struct */ - ibool do_alloc) /*!< in: is an alloc needed */ +dict_mem_referenced_table_name_lookup_set(foreign_ref_info& ref_info, + mem_heap_t* heap) { if (innobase_get_lower_case_table_names() == 2) { - if (do_alloc) { + if (heap) { ulint len; - len = strlen(foreign->referenced_table_name()) + 1; + len = strlen(ref_info.referenced_table_name) + 1; - foreign->ref_info[0].referenced_table_name_lookup = + ref_info.referenced_table_name_lookup = static_cast<char*>( - mem_heap_alloc(foreign->heap, len)); + mem_heap_alloc(heap, len)); } - strcpy(foreign->referenced_table_name_lookup(), - foreign->referenced_table_name()); - innobase_casedn_str(foreign->referenced_table_name_lookup()); + strcpy(ref_info.referenced_table_name_lookup, + ref_info.referenced_table_name); + innobase_casedn_str(ref_info.referenced_table_name_lookup); } else { - foreign->ref_info[0].referenced_table_name_lookup - = foreign->referenced_table_name(); + ref_info.referenced_table_name_lookup + = ref_info.referenced_table_name; } } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index be787981a3e..48251050260 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -11890,31 +11890,19 @@ create_table_info_t::create_foreign_keys() ref_share = m_form->s; } if (ref_share && ref_share->part_info) { - // Iterator over combinations of (partiton, subpartition) - // FIXME: make iterations in other places - for (auto els: *ref_share->part_info) { - err = create_foreign_key( - fk, table, number, local_fk_set, - column_names, ref_column_names, - create_name, operation, - els.first->partition_name, - els.second - ? els.second->partition_name - : NULL); - if (err != DB_SUCCESS) { - return err; - } - } + err = create_foreign_key(create_foreign_key_t( + fk, table, local_fk_set, column_names, + ref_column_names, create_name, operation, + ref_share)); } else #endif /* WITH_PARTITION_STORAGE_ENGINE */ { - err = create_foreign_key( - fk, table, number, local_fk_set, column_names, - ref_column_names, create_name, operation, NULL, - NULL); - if (err != DB_SUCCESS) { - return err; - } + err = create_foreign_key(create_foreign_key_t( + fk, table, local_fk_set, column_names, + ref_column_names, create_name, operation, NULL)); + } + if (err != DB_SUCCESS) { + return err; } } @@ -11944,12 +11932,54 @@ create_table_info_t::create_foreign_keys() } dberr_t -create_table_info_t::create_foreign_key( - FK_info* fk, dict_table_t* table, ulint &number, - dict_foreign_set &local_fk_set, const char** column_names, - const char** ref_column_names, char* create_name, const char* operation, - const char* part_name, const char* subpart_name) -{ +create_table_info_t::get_referenced_table(foreign_ref_info &ref_info, + create_foreign_key_t args, + const char* part_name, + const char* subpart_name) +{ + FK_info *fk = args.fk; + ref_info.referenced_table_name = dict_get_referenced_table( + m_table_name, LEX_STRING_WITH_LEN(fk->ref_db()), + LEX_STRING_WITH_LEN(fk->referenced_table), + part_name, subpart_name, + &ref_info.referenced_table, args.foreign->heap); + + if (!ref_info.referenced_table_name) { + return (DB_OUT_OF_MEMORY); + } + + if (!ref_info.referenced_table_name && m_trx->check_foreigns) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char* bufend; + + bufend = innobase_convert_name( + buf, MAX_TABLE_NAME_LEN, + ref_info.referenced_table_name, + strlen(ref_info.referenced_table_name), m_thd); + buf[bufend - buf] = '\0'; + key_text k(fk); + ib_foreign_warn(m_trx, DB_CANNOT_ADD_CONSTRAINT, + args.create_name, + "%s table %s with foreign key %s " + "constraint failed. Referenced table " + "%s not found in the data dictionary.", + args.operation, args.create_name, k.str(), buf); + return (DB_CANNOT_ADD_CONSTRAINT); + } + return DB_SUCCESS; +} + +dberr_t +create_table_info_t::create_foreign_key(create_foreign_key_t args) +{ + FK_info* fk = args.fk; + dict_table_t* table = args.table; + dict_foreign_set &local_fk_set = args.local_fk_set; + const char** column_names = args.column_names; + const char** ref_column_names = args.ref_column_names; + char* create_name = args.create_name; + const char* operation = args.operation; + TABLE_SHARE *ref_share = args.ref_share; dict_index_t* index = NULL; fkerr_t index_error = FK_SUCCESS; dict_index_t* err_index = NULL; @@ -11959,40 +11989,24 @@ create_table_info_t::create_foreign_key( LEX_CSTRING* col; bool success; - dict_foreign_t* foreign = dict_mem_foreign_create(); + dict_foreign_t* foreign = dict_mem_foreign_create(false); if (!foreign) { return (DB_OUT_OF_MEMORY); } + args.foreign = foreign; + ut_ad(fk->foreign_id.str); { ulint db_len; + // FIXME: concatenate foreign_id and part suffix char id[FN_REFLEN + 1]; const char *foreign_id; size_t id_len; - if (subpart_name) { - ut_ad(part_name); - if (create_subpartition_name( - id, sizeof(id), fk->foreign_id.str, - part_name, subpart_name, - NORMAL_PART_NAME)) { - return (DB_CANNOT_ADD_CONSTRAINT); - } - id_len = strlen(id); - foreign_id = id; - } else if (part_name) { - if (create_partition_name( - id, sizeof(id), fk->foreign_id.str, - part_name, NORMAL_PART_NAME, true)) { - return (DB_CANNOT_ADD_CONSTRAINT); - } - id_len = strlen(id); - foreign_id = id; - } else { - id_len = fk->foreign_id.length; - foreign_id = fk->foreign_id.str; - } + + id_len = fk->foreign_id.length; + foreign_id = fk->foreign_id.str; /* Catenate 'databasename/' to the constraint name specified by the user: we conceive the constraint as @@ -12088,41 +12102,44 @@ create_table_info_t::create_foreign_key( memcpy(foreign->foreign_col_names, column_names, i * sizeof(void*)); - foreign->ref_info[0].referenced_table_name = dict_get_referenced_table( - m_table_name, LEX_STRING_WITH_LEN(fk->ref_db()), - LEX_STRING_WITH_LEN(fk->referenced_table), - part_name, subpart_name, - &foreign->ref_info[0].referenced_table, foreign->heap); - - if (!foreign->referenced_table_name()) { - return (DB_OUT_OF_MEMORY); - } - - if (!foreign->referenced_table() && m_trx->check_foreigns) { - char buf[MAX_TABLE_NAME_LEN + 1] = ""; - char* bufend; - - bufend = innobase_convert_name( - buf, MAX_TABLE_NAME_LEN, - foreign->referenced_table_name(), - strlen(foreign->referenced_table_name()), m_thd); - buf[bufend - buf] = '\0'; - key_text k(fk); - ib_foreign_warn(m_trx, DB_CANNOT_ADD_CONSTRAINT, - create_name, - "%s table %s with foreign key %s " - "constraint failed. Referenced table " - "%s not found in the data dictionary.", - operation, create_name, k.str(), buf); - return (DB_CANNOT_ADD_CONSTRAINT); +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (ref_share) { + ut_ad(ref_share->part_info); + uint parts = ref_share->part_info->get_tot_partitions(); + foreign->ref_info.resize(parts); + auto ref_info_it = foreign->ref_info.begin(); + // Iterator over combinations of (partiton, subpartition) + for (auto els: *ref_share->part_info) { + const char *part_name = els.first->partition_name; + const char *subpart_name = els.second + ? els.second->partition_name + : NULL; + dberr_t err = get_referenced_table( + *ref_info_it, args, part_name, subpart_name); + if (err != DB_SUCCESS) { + return err; + } + ++ref_info_it; + ut_ad(ref_info_it != foreign->ref_info.end()); + } + } else +#endif + { + foreign->ref_info.resize(1); + auto ref_info_it = foreign->ref_info.begin(); + dberr_t err = get_referenced_table( + *ref_info_it, args, NULL, NULL); + if (err != DB_SUCCESS) { + return err; + } } col_it.init(fk->referenced_fields); while ((col = col_it++)) { ref_column_names[j] = mem_heap_strdupl( foreign->heap, col->str, col->length); - if (foreign->referenced_table()) { - success = find_col(foreign->referenced_table(), + if (foreign->referenced_table(0)) { + success = find_col(foreign->referenced_table(0), ref_column_names + j); if (!success) { key_text k(fk); @@ -12148,29 +12165,31 @@ create_table_info_t::create_foreign_key( fields and in the right order, and the types are the same as in foreign->foreign_index */ - if (foreign->referenced_table()) { - index = dict_foreign_find_index( - foreign->referenced_table(), NULL, - ref_column_names, i, foreign->foreign_index, - TRUE, FALSE, &index_error, &err_col, - &err_index); + for (foreign_ref_info& ref_info: foreign->ref_info) { + if (ref_info.referenced_table) { + index = dict_foreign_find_index( + ref_info.referenced_table, NULL, + ref_column_names, i, foreign->foreign_index, + TRUE, FALSE, &index_error, &err_col, + &err_index); - if (!index) { - key_text k(fk); - foreign_push_index_error( - m_trx, operation, create_name, k.str(), - column_names, index_error, err_col, - err_index, foreign->referenced_table()); + if (!index) { + key_text k(fk); + foreign_push_index_error( + m_trx, operation, create_name, k.str(), + column_names, index_error, err_col, + err_index, ref_info.referenced_table); - return (DB_CANNOT_ADD_CONSTRAINT); + return (DB_CANNOT_ADD_CONSTRAINT); + } + } else { + ut_a(m_trx->check_foreigns == FALSE); + index = NULL; } - } else { - ut_a(m_trx->check_foreigns == FALSE); - index = NULL; - } - foreign->ref_info[0].referenced_index = index; - dict_mem_referenced_table_name_lookup_set(foreign, TRUE); + ref_info.referenced_index = index; + dict_mem_referenced_table_name_lookup_set(ref_info, foreign->heap); + } foreign->referenced_col_names = static_cast<const char**>( mem_heap_alloc(foreign->heap, i * sizeof(void*))); @@ -21505,12 +21524,14 @@ dict_load_foreigns(THD* thd, dict_table_t* table, TABLE_SHARE* share, return DB_CANNOT_ADD_CONSTRAINT; } - foreign->ref_info[0].referenced_table_name - = mem_heap_strdupl(foreign->heap, buf, len); - if (!foreign->referenced_table_name()) - return DB_OUT_OF_MEMORY; dict_mem_foreign_table_name_lookup_set(foreign, true); - dict_mem_referenced_table_name_lookup_set(foreign, true); + for (foreign_ref_info& ref_info: foreign->ref_info) { + ref_info.referenced_table_name + = mem_heap_strdupl(foreign->heap, buf, len); + if (!ref_info.referenced_table_name) + return DB_OUT_OF_MEMORY; + dict_mem_referenced_table_name_lookup_set(ref_info, foreign->heap); + } foreign->foreign_col_names = static_cast<const char**>( mem_heap_alloc(foreign->heap, foreign->n_fields * sizeof(void*))); diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 4cd2844e92c..9d15d142cf2 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -642,12 +642,26 @@ public: /** Create InnoDB foreign keys from MySQL alter_info. */ dberr_t create_foreign_keys(); - dberr_t create_foreign_key( - FK_info* fk, dict_table_t* table, ulint &number, - dict_foreign_set &local_fk_set, const char** column_names, - const char** ref_column_names, char* create_name, - const char* operation, const char* part_name, - const char* subpart_name); + struct create_foreign_key_t + { + // in/out: + FK_info* fk; dict_table_t* table; + dict_foreign_set &local_fk_set; const char** column_names; + const char** ref_column_names; char* create_name; + const char* operation; TABLE_SHARE *ref_share; + // out: + dict_foreign_t *foreign = NULL; + create_foreign_key_t( + FK_info* _fk, dict_table_t* _table, + dict_foreign_set &_local_fk_set, const char** _column_names, + const char** _ref_column_names, char* _create_name, + const char* _operation, TABLE_SHARE *_ref_share) : + fk{_fk}, table{_table}, + local_fk_set{_local_fk_set}, column_names{_column_names}, + ref_column_names{_ref_column_names}, create_name{_create_name}, + operation{_operation}, ref_share{_ref_share} {} + }; + dberr_t create_foreign_key(create_foreign_key_t args); /** Create the internal innodb table. @param create_fk whether to add FOREIGN KEY constraints */ @@ -794,6 +808,11 @@ private: /** Table flags2 */ ulint m_flags2; + + dberr_t get_referenced_table(foreign_ref_info &ref_info, + create_foreign_key_t args, + const char* part_name, + const char* subpart_name); }; /** diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 7cd89702d65..83e45b3df6f 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -2637,12 +2637,14 @@ innobase_init_foreign( foreign->heap, column_names[i]); } - foreign->ref_info[0].referenced_index = referenced_index; - foreign->ref_info[0].referenced_table = referenced_table; + for (foreign_ref_info& ref_info: foreign->ref_info) { + ref_info.referenced_index = referenced_index; + ref_info.referenced_table = referenced_table; - foreign->ref_info[0].referenced_table_name = mem_heap_strdup( - foreign->heap, referenced_table_name); - dict_mem_referenced_table_name_lookup_set(foreign, TRUE); + ref_info.referenced_table_name = mem_heap_strdup( + foreign->heap, referenced_table_name); + dict_mem_referenced_table_name_lookup_set(ref_info, foreign->heap); + } foreign->referenced_col_names = static_cast<const char**>( mem_heap_alloc(foreign->heap, diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 6234a92b770..8333e97f6fc 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -57,6 +57,7 @@ Created 1/8/1996 Heikki Tuuri /* Forward declaration. */ struct ib_rbt_t; +struct foreign_ref_info; /** Type flags of an index: OR'ing of the flags is allowed to define a combination of types */ @@ -430,7 +431,7 @@ dict_mem_index_free( Creates and initializes a foreign constraint memory object. @return own: foreign constraint struct */ dict_foreign_t* -dict_mem_foreign_create(void); +dict_mem_foreign_create(bool add_refinfo= true); // FIXME: remove add_refinfo /*=========================*/ /**********************************************************************//** @@ -450,10 +451,8 @@ lower_case_table_names. If that is 0 or 1, referenced_table_name_lookup will point to referenced_table_name. If 2, then another string is allocated from the heap and set to lower case. */ void -dict_mem_referenced_table_name_lookup_set( -/*======================================*/ - dict_foreign_t* foreign, /*!< in/out: foreign struct */ - ibool do_alloc); /*!< in: is an alloc needed */ +dict_mem_referenced_table_name_lookup_set(foreign_ref_info& ref_info, + mem_heap_t* heap); /** Fills the dependent virtual columns in a set. Reason for being dependent are @@ -1405,7 +1404,7 @@ typedef std::set<dict_v_col_t*, std::less<dict_v_col_t*>, ut_allocator<dict_v_col_t*> > dict_vcol_set; -struct dict_foreign_ref_info { +struct foreign_ref_info { char* referenced_table_name;/*!< referenced table name */ char* referenced_table_name_lookup; /*!< referenced table name for dict lookup*/ @@ -1417,7 +1416,7 @@ struct dict_foreign_ref_info { { const dict_index_t* m_index; check_index(const dict_index_t* index) : m_index(index) {} - bool operator()(const dict_foreign_ref_info& i) const + bool operator()(const foreign_ref_info& i) const { return i.referenced_index == m_index; } @@ -1427,14 +1426,15 @@ struct dict_foreign_ref_info { { const dict_table_t* m_table; check_table(const dict_table_t* table) : m_table(table) {} - bool operator()(const dict_foreign_ref_info& i) const + bool operator()(const foreign_ref_info& i) const { return i.referenced_table == m_table; } }; }; -typedef std::vector<dict_foreign_ref_info> ref_info_seq; +typedef std::vector<foreign_ref_info> ref_info_seq; +class FK_info; /** Data structure for a foreign key constraint; an example: FOREIGN KEY (A, B) REFERENCES TABLE2 (C, D). Most fields will be @@ -1463,15 +1463,15 @@ struct dict_foreign_t{ ut_ad(ref_info.size() > 0); return ref_info[0].referenced_table_name; } - char* referenced_table_name_lookup() + char* referenced_table_name_lookup() { ut_ad(ref_info.size() > 0); return ref_info[0].referenced_table_name_lookup; } - dict_table_t* referenced_table() const + dict_table_t* referenced_table(uint i = 0) const // FIXME: remove default value { - ut_ad(ref_info.size() > 0); - return ref_info[0].referenced_table; + ut_ad(ref_info.size() > i); + return ref_info[i].referenced_table; } dict_index_t* referenced_index() const { @@ -1495,6 +1495,7 @@ struct dict_foreign_t{ dict_foreign_t() // used in i_s_sys_foreign_fill_table() { + // FIXME: do something with it? ref_info.resize(1); } }; @@ -1540,7 +1541,7 @@ struct dict_foreign_with_index { bool operator()(const dict_foreign_t* f) const { return(std::any_of(f->ref_info.begin(), f->ref_info.end(), - dict_foreign_ref_info::check_index(m_index))); + foreign_ref_info::check_index(m_index))); } const dict_index_t* m_index; @@ -1572,7 +1573,7 @@ struct dict_foreign_different_tables { bool operator()(const dict_foreign_t* f) const { return(std::none_of(f->ref_info.begin(), f->ref_info.end(), - dict_foreign_ref_info + foreign_ref_info ::check_table(f->foreign_table))); } }; |