revision-id: d6feda205af1f05fa7143501674a2d8c28fda561 (mariadb-galera-10.0.37-2-gd6feda205af) parent(s): c2caca02ac39454e18db8de563e7e7c8eaf8b1c7 368eda060f5922929eb4741e97b37a205591bdf3 author: Jan Lindström committer: Jan Lindström timestamp: 2019-02-01 11:02:03 +0200 message: Merge tag 'mariadb-10.0.38' into 10.0-galera CMakeLists.txt | 10 +- client/CMakeLists.txt | 2 +- client/mysqltest.cc | 51 +- cmake/build_configurations/mysql_release.cmake | 1 - cmake/ssl.cmake | 11 +- cmake/zlib.cmake | 5 - config.h.cmake | 6 +- include/my_global.h | 2 +- include/my_valgrind.h | 4 +- include/mysql.h | 2 +- include/mysql.h.pp | 2 +- include/mysql/service_kill_statement.h | 4 +- libmysqld/examples/CMakeLists.txt | 2 +- mysql-test/disabled.def | 1 + mysql-test/lib/v1/mysql-test-run.pl | 2 +- mysql-test/mysql-test-run.pl | 2 +- mysql-test/r/auto_increment_ranges_innodb.result | 14 + mysql-test/r/bigint.result | 11 + mysql-test/r/func_group_innodb.result | 30 + mysql-test/r/huge_frm-6224.result | 2 + mysql-test/r/innodb_ext_key.result | 95 + mysql-test/r/mysql.result | 26 + mysql-test/r/mysqldump.result | 6 +- mysql-test/r/partition.result | 100 + mysql-test/r/partition_innodb.result | 26 + mysql-test/r/range_innodb.result | 42 + mysql-test/r/read_only.result | 15 +- mysql-test/r/row-checksum-old.result | 16 + mysql-test/r/row-checksum.result | 16 + mysql-test/r/stat_tables.result | 19 + mysql-test/r/stat_tables_innodb.result | 19 + mysql-test/r/subselect2.result | 22 + mysql-test/r/subselect_exists2in.result | 4 +- mysql-test/r/subselect_mat.result | 16 + mysql-test/r/union.result | 38 + mysql-test/r/view.result | 4 +- .../suite/engines/iuds/r/insert_number.result | 100 + .../engines/iuds/r/update_delete_number.result | 17 + .../suite/innodb/r/alter_candidate_key.result | 107 + mysql-test/suite/innodb/r/foreign_key.result | 33 + mysql-test/suite/innodb/r/innodb-alter.result | 159 +- mysql-test/suite/innodb/r/innodb-index.result | 33 + .../suite/innodb/r/innodb-table-online.result | 11 - .../suite/innodb/r/innodb-virtual-columns.result | 15 + mysql-test/suite/innodb/r/innodb_28867993.result | 9 + mysql-test/suite/innodb/t/alter_candidate_key.test | 72 + mysql-test/suite/innodb/t/foreign_key.test | 31 + mysql-test/suite/innodb/t/innodb-alter.test | 114 +- mysql-test/suite/innodb/t/innodb-index.test | 30 + mysql-test/suite/innodb/t/innodb-table-online.test | 4 - .../suite/innodb/t/innodb-virtual-columns.test | 11 + mysql-test/suite/innodb/t/innodb_28867993.test | 12 + .../perfschema/r/dml_setup_instruments.result | 4 +- .../suite/perfschema/t/dml_setup_instruments.test | 5 +- mysql-test/suite/roles/flush_roles-17898.result | 13 + mysql-test/suite/roles/flush_roles-17898.test | 11 + mysql-test/suite/rpl/r/rpl_idempotency.result | 12 + .../suite/rpl/r/rpl_row_big_table_id_32bit.result | 38 + .../suite/rpl/r/rpl_row_big_table_id_64bit.result | 38 + mysql-test/suite/rpl/t/rpl_idempotency.test | 21 + mysql-test/suite/rpl/t/rpl_row_big_table_id.inc | 56 + .../suite/rpl/t/rpl_row_big_table_id_32bit.test | 11 + .../suite/rpl/t/rpl_row_big_table_id_64bit.test | 11 + .../sys_vars/r/table_definition_cache_basic.result | 16 +- .../sys_vars/t/table_definition_cache_basic.test | 6 +- mysql-test/t/auto_increment_ranges_innodb.test | 13 + mysql-test/t/bigint.test | 9 + mysql-test/t/func_group_innodb.test | 26 + mysql-test/t/huge_frm-6224.test | 11 +- mysql-test/t/innodb_ext_key.test | 106 + mysql-test/t/mysql.test | 22 + mysql-test/t/mysqldump.test | 2 +- mysql-test/t/partition.test | 61 + mysql-test/t/partition_innodb.test | 30 + mysql-test/t/range_innodb.test | 42 + mysql-test/t/read_only.test | 21 +- mysql-test/t/row-checksum.test | 17 + mysql-test/t/stat_tables.test | 17 + mysql-test/t/subselect2.test | 20 + mysql-test/t/subselect_mat.test | 13 + mysql-test/t/union.test | 35 + mysql-test/unstable-tests | 119 +- mysys/mf_iocache.c | 4 + mysys/my_file.c | 7 +- mysys/my_pread.c | 26 +- mysys/my_read.c | 48 +- mysys/safemalloc.c | 2 +- res | 22 - scripts/mysql_install_db.sh | 19 +- scripts/mytop.sh | 19 +- sql-common/client.c | 30 +- sql/CMakeLists.txt | 2 +- sql/handler.h | 12 +- sql/item.h | 4 + sql/item_cmpfunc.cc | 190 +- sql/item_cmpfunc.h | 5 + sql/log.cc | 6 +- sql/log_event.cc | 2 +- sql/mysql_install_db.cc | 72 +- sql/opt_range.cc | 16 +- sql/partition_info.cc | 54 +- sql/partition_info.h | 1 + sql/sql_acl.cc | 115 +- sql/sql_array.h | 15 +- sql/sql_const.h | 12 +- sql/sql_lex.cc | 2 + sql/sql_parse.cc | 7 + sql/sql_repl.cc | 6 +- sql/sql_select.cc | 4 + sql/sql_statistics.cc | 43 + sql/sql_statistics.h | 1 + sql/sql_table.cc | 80 +- sql/sql_type_int.h | 28 + sql/sql_update.cc | 2 +- sql/sql_yacc.yy | 23 +- sql/sys_vars.cc | 8 +- sql/table.cc | 48 +- sql/table.h | 2 +- sql/table_cache.cc | 5 +- sql/unireg.h | 2 +- storage/connect/global.h | 6 +- storage/connect/ha_connect.cc | 4 +- storage/connect/jsonudf.cpp | 12 +- .../mysql-test/connect/r/jdbc_oracle.result | 18 +- .../mysql-test/connect/r/jdbc_postgresql.result | 10 +- .../connect/mysql-test/connect/r/part_table.result | 4 +- .../connect/mysql-test/connect/t/part_table.test | 2 +- storage/connect/plugutil.cpp | 28 +- storage/connect/reldef.cpp | 11 +- storage/connect/tabfmt.h | 2 +- storage/connect/tabjson.cpp | 52 +- storage/connect/tabjson.h | 8 +- storage/connect/tabodbc.cpp | 317 +-- storage/connect/tabxml.cpp | 292 +-- storage/connect/tabxml.h | 6 +- storage/connect/user_connect.cc | 4 +- storage/innobase/buf/buf0buf.cc | 172 +- storage/innobase/dict/dict0dict.cc | 7 +- storage/innobase/dict/dict0mem.cc | 4 +- storage/innobase/fil/fil0fil.cc | 27 +- storage/innobase/fts/fts0fts.cc | 20 +- storage/innobase/handler/ha_innodb.cc | 103 +- storage/innobase/handler/ha_innodb.h | 2 +- storage/innobase/handler/handler0alter.cc | 174 +- storage/innobase/include/buf0buf.h | 6 +- storage/innobase/include/dict0mem.h | 4 +- storage/innobase/include/fil0fil.h | 20 +- storage/innobase/include/os0file.h | 6 +- storage/innobase/include/page0page.h | 15 +- storage/innobase/include/page0zip.h | 15 - storage/innobase/include/univ.i | 13 +- storage/innobase/os/os0proc.cc | 3 - storage/innobase/page/page0page.cc | 42 - storage/innobase/page/page0zip.cc | 95 +- storage/innobase/row/row0ftsort.cc | 7 +- storage/innobase/row/row0merge.cc | 5 +- storage/innobase/row/row0mysql.cc | 6 +- storage/innobase/row/row0sel.cc | 4 +- storage/innobase/srv/srv0start.cc | 4 + storage/tokudb/PerconaFT/COPYING.APACHEv2 | 174 ++ storage/tokudb/PerconaFT/README.md | 5 +- storage/tokudb/PerconaFT/ft/txn/txn_manager.h | 4 +- .../tokudb/PerconaFT/locktree/concurrent_tree.cc | 14 + .../tokudb/PerconaFT/locktree/concurrent_tree.h | 14 + storage/tokudb/PerconaFT/locktree/keyrange.cc | 13 + storage/tokudb/PerconaFT/locktree/keyrange.h | 13 + storage/tokudb/PerconaFT/locktree/lock_request.cc | 13 + storage/tokudb/PerconaFT/locktree/lock_request.h | 13 + storage/tokudb/PerconaFT/locktree/locktree.cc | 13 + storage/tokudb/PerconaFT/locktree/locktree.h | 13 + storage/tokudb/PerconaFT/locktree/manager.cc | 13 + storage/tokudb/PerconaFT/locktree/range_buffer.cc | 13 + storage/tokudb/PerconaFT/locktree/range_buffer.h | 13 + storage/tokudb/PerconaFT/locktree/treenode.cc | 13 + storage/tokudb/PerconaFT/locktree/treenode.h | 13 + storage/tokudb/PerconaFT/locktree/txnid_set.cc | 13 + storage/tokudb/PerconaFT/locktree/txnid_set.h | 13 + storage/tokudb/PerconaFT/locktree/wfg.cc | 13 + storage/tokudb/PerconaFT/locktree/wfg.h | 13 + .../PerconaFT/portability/toku_instr_mysql.cc | 12 +- .../PerconaFT/portability/toku_instr_mysql.h | 11 +- .../tokudb/PerconaFT/portability/toku_pthread.h | 78 +- storage/tokudb/PerconaFT/util/growable_array.h | 13 + storage/tokudb/PerconaFT/util/omt.cc | 2261 +++++++++++--------- storage/tokudb/PerconaFT/util/omt.h | 13 + storage/tokudb/ha_tokudb.cc | 10 + storage/tokudb/hatoku_hton.cc | 4 +- storage/tokudb/hatoku_hton.h | 1 - .../mysql-test/tokudb/t/change_column_bin.py | 0 .../tokudb/t/change_column_bin_rename.py | 0 .../mysql-test/tokudb/t/change_column_char.py | 0 .../tokudb/t/change_column_char_binary.py | 0 .../tokudb/t/change_column_char_charbinary.py | 0 .../tokudb/t/change_column_char_rename.py | 0 .../mysql-test/tokudb/t/change_column_int.py | 0 .../mysql-test/tokudb/t/change_column_int_key.py | 0 .../tokudb/t/change_column_int_not_supported.py | 0 .../tokudb/t/change_column_int_rename.py | 0 .../tokudb/mysql-test/tokudb_bugs/r/PS-4979.result | 2 + .../tokudb/mysql-test/tokudb_bugs/t/PS-4979.test | 13 + storage/tokudb/tokudb_background.cc | 4 +- storage/tokudb/tokudb_sysvars.cc | 14 +- storage/tokudb/tokudb_sysvars.h | 4 +- storage/xtradb/buf/buf0buf.cc | 174 +- storage/xtradb/dict/dict0dict.cc | 7 +- storage/xtradb/dict/dict0mem.cc | 4 +- storage/xtradb/fil/fil0fil.cc | 36 +- storage/xtradb/fts/fts0fts.cc | 20 +- storage/xtradb/fts/fts0pars.cc | 4 +- storage/xtradb/fts/fts0pars.y | 4 +- storage/xtradb/handler/ha_innodb.cc | 103 +- storage/xtradb/handler/ha_innodb.h | 8 +- storage/xtradb/handler/handler0alter.cc | 141 +- storage/xtradb/include/buf0buf.h | 6 +- storage/xtradb/include/data0type.ic | 1 + storage/xtradb/include/dict0mem.h | 7 +- storage/xtradb/include/fil0fil.h | 20 +- storage/xtradb/include/page0page.h | 18 +- storage/xtradb/include/univ.i | 15 +- storage/xtradb/log/log0online.cc | 41 +- storage/xtradb/os/os0proc.cc | 3 - storage/xtradb/page/page0page.cc | 46 - storage/xtradb/page/page0zip.cc | 87 +- storage/xtradb/row/row0ftsort.cc | 7 +- storage/xtradb/row/row0import.cc | 9 +- storage/xtradb/row/row0mysql.cc | 15 +- storage/xtradb/row/row0sel.cc | 5 +- storage/xtradb/srv/srv0start.cc | 3 + support-files/mysql.server.sh | 6 +- unittest/mysys/lf-t.c | 5 - unittest/mysys/my_atomic-t.c | 17 +- unittest/mysys/thr_template.c | 31 +- unittest/mysys/waiting_threads-t.c | 4 +- win/packaging/heidisql.cmake | 2 +- 234 files changed, 5459 insertions(+), 2902 deletions(-) diff --cc storage/innobase/handler/ha_innodb.cc index 2244cd1101a,f7c8573cd62..ecf2318bf81 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@@ -9825,446 -9041,6 +9822,435 @@@ next_record return(HA_ERR_END_OF_FILE); } - /************************************************************************* - */ - - void - ha_innobase::ft_end() - { - fprintf(stderr, "ft_end()\n"); - - rnd_end(); - } +#ifdef WITH_WSREP +extern dict_index_t* +wsrep_dict_foreign_find_index( + dict_table_t* table, + const char** col_names, + const char** columns, + ulint n_cols, + dict_index_t* types_idx, + ibool check_charsets, + ulint check_null); + +inline +const char* +wsrep_key_type_to_str(wsrep_key_type type) +{ + switch (type) { + case WSREP_KEY_SHARED: + return "shared"; + case WSREP_KEY_SEMI: + return "semi"; + case WSREP_KEY_EXCLUSIVE: + return "exclusive"; + }; + return "unknown"; +} + +ulint +wsrep_append_foreign_key( +/*===========================*/ + trx_t* trx, /*!< in: trx */ + dict_foreign_t* foreign, /*!< in: foreign key constraint */ + const rec_t* rec, /*!<in: clustered index record */ + dict_index_t* index, /*!<in: clustered index */ + ibool referenced, /*!<in: is check for referenced table */ + wsrep_key_type key_type) /*!< in: access type of this key + (shared, exclusive, semi...) */ +{ + ut_a(trx); + THD* thd = (THD*)trx->mysql_thd; + ulint rcode = DB_SUCCESS; + char cache_key[513] = {'\0'}; + int cache_key_len; + bool const copy = true; + + if (!wsrep_on(trx->mysql_thd) || + wsrep_thd_exec_mode(thd) != LOCAL_STATE) + return DB_SUCCESS; + + if (!thd || !foreign || + (!foreign->referenced_table && !foreign->foreign_table)) + { + WSREP_INFO("FK: %s missing in: %s", + (!thd) ? "thread" : + ((!foreign) ? "constraint" : + ((!foreign->referenced_table) ? + "referenced table" : "foreign table")), + (thd && wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_DEBUG("pulling %s table into cache", + (referenced) ? "referenced" : "foreign"); + mutex_enter(&(dict_sys->mutex)); + if (referenced) + { + foreign->referenced_table = + dict_table_get_low( + foreign->referenced_table_name_lookup); + if (foreign->referenced_table) + { + foreign->referenced_index = + wsrep_dict_foreign_find_index( + foreign->referenced_table, NULL, + foreign->referenced_col_names, + foreign->n_fields, + foreign->foreign_index, + TRUE, FALSE); + } + } + else + { + foreign->foreign_table = + dict_table_get_low( + foreign->foreign_table_name_lookup); + if (foreign->foreign_table) + { + foreign->foreign_index = + wsrep_dict_foreign_find_index( + foreign->foreign_table, NULL, + foreign->foreign_col_names, + foreign->n_fields, + foreign->referenced_index, + TRUE, FALSE); + } + } + mutex_exit(&(dict_sys->mutex)); + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_WARN("FK: %s missing in query: %s", + (!foreign->referenced_table) ? + "referenced table" : "foreign table", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + byte key[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + ulint len = WSREP_MAX_SUPPORTED_KEY_LENGTH; + + dict_index_t *idx_target = (referenced) ? + foreign->referenced_index : index; + dict_index_t *idx = (referenced) ? + UT_LIST_GET_FIRST(foreign->referenced_table->indexes) : + UT_LIST_GET_FIRST(foreign->foreign_table->indexes); + int i = 0; + while (idx != NULL && idx != idx_target) { + if (innobase_strcasecmp (idx->name, innobase_index_reserve_name) != 0) { + i++; + } + idx = UT_LIST_GET_NEXT(indexes, idx); + } + ut_a(idx); + key[0] = (char)i; + + rcode = wsrep_rec_get_foreign_key( + &key[1], &len, rec, index, idx, + wsrep_protocol_version > 1); + + if (rcode != DB_SUCCESS) { + WSREP_ERROR( + "FK key set failed: %lu (%lu %s), index: %s %s, %s", + rcode, referenced, wsrep_key_type_to_str(key_type), + (index && index->name) ? index->name : + "void index", + (index && index->table_name) ? index->table_name : + "void table", + wsrep_thd_query(thd)); + return DB_ERROR; + } + + strncpy(cache_key, + (wsrep_protocol_version > 1) ? + ((referenced) ? + foreign->referenced_table->name : + foreign->foreign_table->name) : + foreign->foreign_table->name, sizeof(cache_key) - 1); + cache_key_len = strlen(cache_key); +#ifdef WSREP_DEBUG_PRINT + ulint j; + fprintf(stderr, "FK parent key, table: %s %s len: %lu ", + cache_key, (shared) ? "shared" : "exclusive", len+1); + for (j=0; j<len+1; j++) { + fprintf(stderr, " %hhX, ", key[j]); + } + fprintf(stderr, "\n"); +#endif + char *p = strchr(cache_key, '/'); + if (p) { + *p = '\0'; + } else { + WSREP_WARN("unexpected foreign key table %s %s", + foreign->referenced_table->name, + foreign->foreign_table->name); + } + + wsrep_buf_t wkey_part[3]; + wsrep_key_t wkey = {wkey_part, 3}; + if (!wsrep_prepare_key_for_innodb( + (const uchar*)cache_key, + cache_key_len + 1, + (const uchar*)key, len+1, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for cascaded FK: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + key_type, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %lu", rcode)); + WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + return DB_ERROR; + } + + return DB_SUCCESS; +} + +static int +wsrep_append_key( +/*==================*/ + THD *thd, + trx_t *trx, + TABLE_SHARE *table_share, + TABLE *table, + const char* key, + uint16_t key_len, + wsrep_key_type key_type /*!< in: access type of this key + (shared, exclusive, semi...) */ +) +{ + DBUG_ENTER("wsrep_append_key"); + bool const copy = true; +#ifdef WSREP_DEBUG_PRINT + fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s\n Query: %s ", + wsrep_key_type_to_str(key_type), + wsrep_thd_thread_id(thd), trx->id, key_len, + table_share->table_name.str, wsrep_thd_query(thd)); + for (int i=0; i<key_len; i++) { + fprintf(stderr, "%hhX, ", key[i]); + } + fprintf(stderr, "\n"); +#endif + wsrep_buf_t wkey_part[3]; + wsrep_key_t wkey = {wkey_part, 3}; + if (!wsrep_prepare_key_for_innodb( + (const uchar*)table_share->table_cache_key.str, + table_share->table_cache_key.length, + (const uchar*)key, key_len, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + + int rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + key_type, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %d", rcode)); + WSREP_WARN("Appending row key failed: %s, %d", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + DBUG_RETURN(0); +} + +extern void compute_md5_hash(char *digest, const char *buf, int len); +#define MD5_HASH compute_md5_hash + +static bool +referenced_by_foreign_key2(dict_table_t* table, + dict_index_t* index) { + ut_ad(table != NULL); + ut_ad(index != NULL); + + const dict_foreign_set* fks = &table->referenced_set; + for (dict_foreign_set::const_iterator it = fks->begin(); + it != fks->end(); + ++it) + { + dict_foreign_t* foreign = *it; + if (foreign->referenced_index != index) { + continue; + } + ut_ad(table == foreign->referenced_table); + return true; + } + return false; +} + +int +ha_innobase::wsrep_append_keys( +/*==================*/ + THD *thd, + wsrep_key_type key_type, /*!< in: access type of this key + (shared, exclusive, semi...) */ + const uchar* record0, /* in: row in MySQL format */ + const uchar* record1) /* in: row in MySQL format */ +{ + int rcode; + DBUG_ENTER("wsrep_append_keys"); + + bool key_appended = false; + trx_t *trx = thd_to_trx(thd); + + if (table_share && table_share->tmp_table != NO_TMP_TABLE) { + WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s", + wsrep_thd_thread_id(thd), + table_share->tmp_table, + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(0); + } + + if (wsrep_protocol_version == 0) { + uint len; + char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char *key = &keyval[0]; + ibool is_null; + + len = wsrep_store_key_val_for_row( + thd, table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, &is_null); + + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, keyval, + len, key_type); + if (rcode) DBUG_RETURN(rcode); + } + else + { + WSREP_DEBUG("NULL key skipped (proto 0): %s", + wsrep_thd_query(thd)); + } + } else { + ut_a(table->s->keys <= 256); + uint i; + bool hasPK= false; + + for (i=0; i<table->s->keys; ++i) { + KEY* key_info = table->key_info + i; + if (key_info->flags & HA_NOSAME) { + hasPK = true; + } + } + + for (i=0; i<table->s->keys; ++i) { + uint len; + char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char* key0 = &keyval0[1]; + char* key1 = &keyval1[1]; + KEY* key_info = table->key_info + i; + ibool is_null; + + dict_index_t* idx = innobase_get_index(i); + dict_table_t* tab = (idx) ? idx->table : NULL; + + keyval0[0] = (char)i; + keyval1[0] = (char)i; + + if (!tab) { + WSREP_WARN("MySQL-InnoDB key mismatch %s %s", + table->s->table_name.str, + key_info->name); + } + /* !hasPK == table with no PK, must append all non-unique keys */ + if (!hasPK || key_info->flags & HA_NOSAME || + ((tab && + referenced_by_foreign_key2(tab, idx)) || + (!tab && referenced_by_foreign_key()))) { + + len = wsrep_store_key_val_for_row( + thd, table, i, key0, + WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, &is_null); + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, + keyval0, len+1, key_type); + if (rcode) DBUG_RETURN(rcode); + + if (key_info->flags & HA_NOSAME || + key_type == WSREP_KEY_SHARED) + key_appended = true; + } + else + { + WSREP_DEBUG("NULL key skipped: %s", + wsrep_thd_query(thd)); + } + if (record1) { + len = wsrep_store_key_val_for_row( + thd, table, i, key1, + WSREP_MAX_SUPPORTED_KEY_LENGTH, + record1, &is_null); + if (!is_null && memcmp(key0, key1, len)) { + rcode = wsrep_append_key( + thd, trx, table_share, + table, + keyval1, len+1, key_type); + if (rcode) DBUG_RETURN(rcode); + } + } + } + } + } + + /* if no PK, calculate hash of full row, to be the key value */ + if (!key_appended && wsrep_certify_nonPK) { + uchar digest[16]; + int rcode; + + wsrep_calc_row_hash(digest, record0, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, table, + (const char*) digest, 16, + key_type))) { + DBUG_RETURN(rcode); + } + + if (record1) { + wsrep_calc_row_hash( + digest, record1, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, + table, + (const char*) digest, + 16, key_type))) { + DBUG_RETURN(rcode); + } + } + DBUG_RETURN(0); + } + + DBUG_RETURN(0); +} +#endif /* WITH_WSREP */ - /*********************************************************************//** Stores a reference to the current row to 'ref' field of the handle. Note that in the case where we have generated the clustered index for the diff --cc storage/xtradb/handler/ha_innodb.cc index 89539bfeed2,3a7b5b493a2..8c0db0231ed --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@@ -10591,446 -9812,6 +10593,435 @@@ next_record return(HA_ERR_END_OF_FILE); } - /************************************************************************* - */ - - void - ha_innobase::ft_end() - { - fprintf(stderr, "ft_end()\n"); - - rnd_end(); - } +#ifdef WITH_WSREP +extern dict_index_t* +wsrep_dict_foreign_find_index( + dict_table_t* table, + const char** col_names, + const char** columns, + ulint n_cols, + dict_index_t* types_idx, + ibool check_charsets, + ulint check_null); + +inline +const char* +wsrep_key_type_to_str(wsrep_key_type type) +{ + switch (type) { + case WSREP_KEY_SHARED: + return "shared"; + case WSREP_KEY_SEMI: + return "semi"; + case WSREP_KEY_EXCLUSIVE: + return "exclusive"; + }; + return "unknown"; +} + +ulint +wsrep_append_foreign_key( +/*===========================*/ + trx_t* trx, /*!< in: trx */ + dict_foreign_t* foreign, /*!< in: foreign key constraint */ + const rec_t* rec, /*!<in: clustered index record */ + dict_index_t* index, /*!<in: clustered index */ + ibool referenced, /*!<in: is check for referenced table */ + wsrep_key_type key_type) /*!< in: access type of this key + (shared, exclusive, semi...) */ +{ + ut_a(trx); + THD* thd = (THD*)trx->mysql_thd; + ulint rcode = DB_SUCCESS; + char cache_key[513] = {'\0'}; + int cache_key_len; + bool const copy = true; + + if (!wsrep_on(trx->mysql_thd) || + wsrep_thd_exec_mode(thd) != LOCAL_STATE) + return DB_SUCCESS; + + if (!thd || !foreign || + (!foreign->referenced_table && !foreign->foreign_table)) + { + WSREP_INFO("FK: %s missing in: %s", + (!thd) ? "thread" : + ((!foreign) ? "constraint" : + ((!foreign->referenced_table) ? + "referenced table" : "foreign table")), + (thd && wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_DEBUG("pulling %s table into cache", + (referenced) ? "referenced" : "foreign"); + mutex_enter(&(dict_sys->mutex)); + if (referenced) + { + foreign->referenced_table = + dict_table_get_low( + foreign->referenced_table_name_lookup); + if (foreign->referenced_table) + { + foreign->referenced_index = + wsrep_dict_foreign_find_index( + foreign->referenced_table, NULL, + foreign->referenced_col_names, + foreign->n_fields, + foreign->foreign_index, + TRUE, FALSE); + } + } + else + { + foreign->foreign_table = + dict_table_get_low( + foreign->foreign_table_name_lookup); + if (foreign->foreign_table) + { + foreign->foreign_index = + wsrep_dict_foreign_find_index( + foreign->foreign_table, NULL, + foreign->foreign_col_names, + foreign->n_fields, + foreign->referenced_index, + TRUE, FALSE); + } + } + mutex_exit(&(dict_sys->mutex)); + } + + if ( !((referenced) ? + foreign->referenced_table : foreign->foreign_table)) + { + WSREP_WARN("FK: %s missing in query: %s", + (!foreign->referenced_table) ? + "referenced table" : "foreign table", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + byte key[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + ulint len = WSREP_MAX_SUPPORTED_KEY_LENGTH; + + dict_index_t *idx_target = (referenced) ? + foreign->referenced_index : index; + dict_index_t *idx = (referenced) ? + UT_LIST_GET_FIRST(foreign->referenced_table->indexes) : + UT_LIST_GET_FIRST(foreign->foreign_table->indexes); + int i = 0; + while (idx != NULL && idx != idx_target) { + if (innobase_strcasecmp (idx->name, innobase_index_reserve_name) != 0) { + i++; + } + idx = UT_LIST_GET_NEXT(indexes, idx); + } + ut_a(idx); + key[0] = (char)i; + + rcode = wsrep_rec_get_foreign_key( + &key[1], &len, rec, index, idx, + wsrep_protocol_version > 1); + + if (rcode != DB_SUCCESS) { + WSREP_ERROR( + "FK key set failed: %lu (%lu %s), index: %s %s, %s", + rcode, referenced, wsrep_key_type_to_str(key_type), + (index && index->name) ? index->name : + "void index", + (index && index->table_name) ? index->table_name : + "void table", + wsrep_thd_query(thd)); + return DB_ERROR; + } + + strncpy(cache_key, + (wsrep_protocol_version > 1) ? + ((referenced) ? + foreign->referenced_table->name : + foreign->foreign_table->name) : + foreign->foreign_table->name, sizeof(cache_key) - 1); + cache_key_len = strlen(cache_key); +#ifdef WSREP_DEBUG_PRINT + ulint j; + fprintf(stderr, "FK parent key, table: %s %s len: %lu ", + cache_key, (shared) ? "shared" : "exclusive", len+1); + for (j=0; j<len+1; j++) { + fprintf(stderr, " %hhX, ", key[j]); + } + fprintf(stderr, "\n"); +#endif + char *p = strchr(cache_key, '/'); + if (p) { + *p = '\0'; + } else { + WSREP_WARN("unexpected foreign key table %s %s", + foreign->referenced_table->name, + foreign->foreign_table->name); + } + + wsrep_buf_t wkey_part[3]; + wsrep_key_t wkey = {wkey_part, 3}; + if (!wsrep_prepare_key_for_innodb( + (const uchar*)cache_key, + cache_key_len + 1, + (const uchar*)key, len+1, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for cascaded FK: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + return DB_ERROR; + } + rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + key_type, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %lu", rcode)); + WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + return DB_ERROR; + } + + return DB_SUCCESS; +} + +static int +wsrep_append_key( +/*==================*/ + THD *thd, + trx_t *trx, + TABLE_SHARE *table_share, + TABLE *table, + const char* key, + uint16_t key_len, + wsrep_key_type key_type /*!< in: access type of this key + (shared, exclusive, semi...) */ +) +{ + DBUG_ENTER("wsrep_append_key"); + bool const copy = true; +#ifdef WSREP_DEBUG_PRINT + fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s\n Query: %s ", + wsrep_key_type_to_str(key_type), + wsrep_thd_thread_id(thd), trx->id, key_len, + table_share->table_name.str, wsrep_thd_query(thd)); + for (int i=0; i<key_len; i++) { + fprintf(stderr, "%hhX, ", key[i]); + } + fprintf(stderr, "\n"); +#endif + wsrep_buf_t wkey_part[3]; + wsrep_key_t wkey = {wkey_part, 3}; + if (!wsrep_prepare_key_for_innodb( + (const uchar*)table_share->table_cache_key.str, + table_share->table_cache_key.length, + (const uchar*)key, key_len, + wkey_part, + (size_t*)&wkey.key_parts_num)) { + WSREP_WARN("key prepare failed for: %s", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + + int rcode = (int)wsrep->append_key( + wsrep, + wsrep_ws_handle(thd, trx), + &wkey, + 1, + key_type, + copy); + if (rcode) { + DBUG_PRINT("wsrep", ("row key failed: %d", rcode)); + WSREP_WARN("Appending row key failed: %s, %d", + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void", rcode); + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + } + DBUG_RETURN(0); +} + +extern void compute_md5_hash(char *digest, const char *buf, int len); +#define MD5_HASH compute_md5_hash + +static bool +referenced_by_foreign_key2(dict_table_t* table, + dict_index_t* index) { + ut_ad(table != NULL); + ut_ad(index != NULL); + + const dict_foreign_set* fks = &table->referenced_set; + for (dict_foreign_set::const_iterator it = fks->begin(); + it != fks->end(); + ++it) + { + dict_foreign_t* foreign = *it; + if (foreign->referenced_index != index) { + continue; + } + ut_ad(table == foreign->referenced_table); + return true; + } + return false; +} + +int +ha_innobase::wsrep_append_keys( +/*==================*/ + THD *thd, + wsrep_key_type key_type, /*!< in: access type of this key + (shared, exclusive, semi...) */ + const uchar* record0, /* in: row in MySQL format */ + const uchar* record1) /* in: row in MySQL format */ +{ + int rcode; + DBUG_ENTER("wsrep_append_keys"); + + bool key_appended = false; + trx_t *trx = thd_to_trx(thd); + + if (table_share && table_share->tmp_table != NO_TMP_TABLE) { + WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s", + wsrep_thd_thread_id(thd), + table_share->tmp_table, + (wsrep_thd_query(thd)) ? + wsrep_thd_query(thd) : "void"); + DBUG_RETURN(0); + } + + if (wsrep_protocol_version == 0) { + uint len; + char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char *key = &keyval[0]; + ibool is_null; + + len = wsrep_store_key_val_for_row( + thd, table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, prebuilt, &is_null); + + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, keyval, + len, key_type); + if (rcode) DBUG_RETURN(rcode); + } + else + { + WSREP_DEBUG("NULL key skipped (proto 0): %s", + wsrep_thd_query(thd)); + } + } else { + ut_a(table->s->keys <= 256); + uint i; + bool hasPK= false; + + for (i=0; i<table->s->keys; ++i) { + KEY* key_info = table->key_info + i; + if (key_info->flags & HA_NOSAME) { + hasPK = true; + } + } + + for (i=0; i<table->s->keys; ++i) { + uint len; + char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + char* key0 = &keyval0[1]; + char* key1 = &keyval1[1]; + KEY* key_info = table->key_info + i; + ibool is_null; + + dict_index_t* idx = innobase_get_index(i); + dict_table_t* tab = (idx) ? idx->table : NULL; + + keyval0[0] = (char)i; + keyval1[0] = (char)i; + + if (!tab) { + WSREP_WARN("MySQL-InnoDB key mismatch %s %s", + table->s->table_name.str, + key_info->name); + } + /* !hasPK == table with no PK, must append all non-unique keys */ + if (!hasPK || key_info->flags & HA_NOSAME || + ((tab && + referenced_by_foreign_key2(tab, idx)) || + (!tab && referenced_by_foreign_key()))) { + + len = wsrep_store_key_val_for_row( + thd, table, i, key0, + WSREP_MAX_SUPPORTED_KEY_LENGTH, + record0, prebuilt, &is_null); + if (!is_null) { + rcode = wsrep_append_key( + thd, trx, table_share, table, + keyval0, len+1, key_type); + if (rcode) DBUG_RETURN(rcode); + + if (key_info->flags & HA_NOSAME || + key_type == WSREP_KEY_SHARED) + key_appended = true; + } + else + { + WSREP_DEBUG("NULL key skipped: %s", + wsrep_thd_query(thd)); + } + if (record1) { + len = wsrep_store_key_val_for_row( + thd, table, i, key1, + WSREP_MAX_SUPPORTED_KEY_LENGTH, + record1, prebuilt, &is_null); + if (!is_null && memcmp(key0, key1, len)) { + rcode = wsrep_append_key( + thd, trx, table_share, + table, + keyval1, len+1, key_type); + if (rcode) DBUG_RETURN(rcode); + } + } + } + } + } + + /* if no PK, calculate hash of full row, to be the key value */ + if (!key_appended && wsrep_certify_nonPK) { + uchar digest[16]; + int rcode; + + wsrep_calc_row_hash(digest, record0, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, table, + (const char*) digest, 16, + key_type))) { + DBUG_RETURN(rcode); + } + + if (record1) { + wsrep_calc_row_hash( + digest, record1, table, prebuilt, thd); + if ((rcode = wsrep_append_key(thd, trx, table_share, + table, + (const char*) digest, + 16, key_type))) { + DBUG_RETURN(rcode); + } + } + DBUG_RETURN(0); + } + + DBUG_RETURN(0); +} +#endif /* WITH_WSREP */ - /*********************************************************************//** Stores a reference to the current row to 'ref' field of the handle. Note that in the case where we have generated the clustered index for the