From f5ac718b1db7a012d113b051ef74932c6e0a29df Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Mon, 4 May 2015 12:06:52 +0200 Subject: [PATCH 01/47] Raise version number after cloning 5.5.44 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index fa5486099ce66..904aeda33ab7e 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=44 +MYSQL_VERSION_PATCH=45 MYSQL_VERSION_EXTRA= From e7b6e814bea7a9e21ef864016bde39fd65a7f655 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Sat, 9 May 2015 13:24:01 +0530 Subject: [PATCH 02/47] Bug #19138298 RECORD IN INDEX WAS NOT FOUND ON ROLLBACK, TRYING TO INSERT Scenario: 1. The purge thread takes an undo log record and parses it and forms the record to be purged. We have the primary and secondary keys to locate the actual records. 2. Using the secondary index key, we search in the secondary index. One record is found. 3. Then it is checked if this record can be purged. The answer is we can purge this record. To determine this we look up the clustered index record. Either there is no corresponding clustered index record, or the matching clustered index record is delete marked. 4. Then we check whether the secondary index record is delete marked. We find that it is not delete marked. We report warning in optimized build and assert in debug build. Problem: In step 3, we report that the record is purgeable even though it is not delete marked. This is because of inconsistency between the following members of purge_node_t structure - found_clust, ref and pcur. Solution: In the row_purge_reposition_pcur(), if the persistent cursor restore fails, then reset the purge_node_t->found_clust member. This will keep the members of purge_node_t structure in a consistent state. rb#8813 approved by Marko. --- storage/innobase/include/row0purge.h | 13 ++++- storage/innobase/row/row0purge.c | 72 +++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 13 deletions(-) diff --git a/storage/innobase/include/row0purge.h b/storage/innobase/include/row0purge.h index fa9c9291d5d2a..9a638c80493c1 100644 --- a/storage/innobase/include/row0purge.h +++ b/storage/innobase/include/row0purge.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -111,6 +111,17 @@ struct purge_node_struct{ purge of a row */ }; +#ifdef UNIV_DEBUG +/***********************************************************//** +Validate the persisent cursor in the purge node. The purge node has two +references to the clustered index record - one via the ref member, and the +other via the persistent cursor. These two references must match each +other if the found_clust flag is set. +@return true if the persistent cursor is consistent with the ref member.*/ +ibool +row_purge_validate_pcur(purge_node_t* node); +#endif /* UNIV_DEBUG */ + #ifndef UNIV_NONINL #include "row0purge.ic" #endif diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index efcfdc3bac540..bfda1a47d0acf 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -90,23 +90,23 @@ row_purge_reposition_pcur( purge_node_t* node, /*!< in: row purge node */ mtr_t* mtr) /*!< in: mtr */ { - ibool found; - if (node->found_clust) { - found = btr_pcur_restore_position(mode, &(node->pcur), mtr); + ut_ad(row_purge_validate_pcur(node)); - return(found); - } + node->found_clust = btr_pcur_restore_position( + mode, &(node->pcur), mtr); + + } else { - found = row_search_on_row_ref(&(node->pcur), mode, node->table, - node->ref, mtr); - node->found_clust = found; + node->found_clust = row_search_on_row_ref( + &(node->pcur), mode, node->table, node->ref, mtr); - if (found) { - btr_pcur_store_position(&(node->pcur), mtr); + if (node->found_clust) { + btr_pcur_store_position(&(node->pcur), mtr); + } } - return(found); + return(node->found_clust); } /***********************************************************//** @@ -806,3 +806,51 @@ row_purge_step( return(thr); } + +#ifdef UNIV_DEBUG +/***********************************************************//** +Validate the persisent cursor in the purge node. The purge node has two +references to the clustered index record - one via the ref member, and the +other via the persistent cursor. These two references must match each +other if the found_clust flag is set. +@return true if the persistent cursor is consistent with the ref member.*/ +ibool +row_purge_validate_pcur( + purge_node_t* node) +{ + const rec_t* rec ; + dict_index_t* clust_index; + ulint* offsets; + int st; + + if (!node->found_clust) { + return(TRUE); + } + + if (node->index == NULL) { + return(TRUE); + } + + clust_index = node->pcur.btr_cur.index; + + if (node->pcur.old_stored == BTR_PCUR_OLD_STORED) { + rec = node->pcur.old_rec; + } else { + rec = btr_pcur_get_rec(&node->pcur); + } + + offsets = rec_get_offsets(rec, + clust_index, NULL, ULINT_UNDEFINED, &node->heap); + + st = cmp_dtuple_rec(node->ref, rec, offsets); + + if (st != 0) { + fprintf(stderr, "Purge node pcur validation failed\n"); + dtuple_print(stderr, node->ref); + rec_print(stderr, rec, clust_index); + return(FALSE); + } + + return(TRUE); +} +#endif /* UNIV_DEBUG */ From 515b2203c5913679757fa2cf39f017001f7e29ee Mon Sep 17 00:00:00 2001 From: Ajo Robert Date: Mon, 11 May 2015 16:05:50 +0530 Subject: [PATCH 03/47] Bug #18075170 SQL NODE RESTART REQUIRED TO AVOID DEADLOCK AFTER RESTORE Analysis -------- Accessing the restored NDB table in an active multi-statement transaction was resulting in deadlock found error. MySQL Server needs to discover metadata of NDB table from data nodes after table is restored from backup. Metadata discovery happens on the first access to restored table. Current code mandates this statement to be the first one in the transaction. This is because discover needs exclusive metadata lock on the table. Lock upgrade at this point can lead to MDL deadlock and the code was written at the time when MDL deadlock detector was not present. In case when discovery attempted in the statement other than the first one in transaction ER_LOCK_DEADLOCK error is reported pessimistically. Fix: --- Removed the constraint as any potential deadlock will be handled by deadlock detector. Also changed code in discover to keep metadata locks of active transaction. Same issue was present in table auto repair scenario. Same fix is added in repair path also. --- ...e_recover.result => myisam_recover.result} | 57 ++++++++++++-- .../suite/ndb/r/ndb_restore_discover.result | 33 ++++++++ .../suite/ndb/t/ndb_restore_discover.test | 70 +++++++++++++++++ ...r-master.opt => myisam_recover-master.opt} | 0 ...merge_recover.test => myisam_recover.test} | 75 +++++++++++++++++-- sql/sql_base.cc | 58 ++++++++++++-- 6 files changed, 276 insertions(+), 17 deletions(-) rename mysql-test/r/{merge_recover.result => myisam_recover.result} (62%) create mode 100644 mysql-test/suite/ndb/r/ndb_restore_discover.result create mode 100644 mysql-test/suite/ndb/t/ndb_restore_discover.test rename mysql-test/t/{merge_recover-master.opt => myisam_recover-master.opt} (100%) rename mysql-test/t/{merge_recover.test => myisam_recover.test} (62%) diff --git a/mysql-test/r/merge_recover.result b/mysql-test/r/myisam_recover.result similarity index 62% rename from mysql-test/r/merge_recover.result rename to mysql-test/r/myisam_recover.result index 871c12ca4c001..3c8639e0518a4 100644 --- a/mysql-test/r/merge_recover.result +++ b/mysql-test/r/myisam_recover.result @@ -1,5 +1,7 @@ # -# Test of MyISAM MRG tables with corrupted children. +# Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted +# children.. +# # Run with --myisam-recover=force option. # # Preparation: we need to make sure that the merge parent @@ -44,20 +46,20 @@ drop procedure p_create; # Switching to connection 'default' # # -# We have to disable the ps-protocol, to avoid +# We have to disable the ps-protocol, to avoid # "Prepared statement needs to be re-prepared" errors # -- table def versions change all the time with full table cache. -# +# drop table if exists t1, t1_mrg, t1_copy; # # Prepare a MERGE engine table, that refers to a corrupted # child. -# +# create table t1 (a int, key(a)) engine=myisam; create table t1_mrg (a int) union (t1) engine=merge; # # Create a table with a corrupted index file: -# save an old index file, insert more rows, +# save an old index file, insert more rows, # overwrite the new index file with the old one. # insert into t1 (a) values (1), (2), (3); @@ -101,3 +103,48 @@ execute stmt; deallocate prepare stmt; set @@global.table_definition_cache=default; set @@global.table_open_cache=default; +# +# 18075170 - sql node restart required to avoid deadlock after +# restore +# +# Check that auto-repair for MyISAM tables can now happen in the +# middle of transaction, without aborting it. +create table t1 (a int, key(a)) engine=myisam; +create table t2 (a int); +insert into t2 values (1); +# Create a table with a corrupted index file: +# save an old index file, insert more rows, +# overwrite the new index file with the old one. +insert into t1 (a) values (1); +flush table t1; +insert into t1 (a) values (4); +flush table t1; +# Check table is needed to mark the table as crashed. +check table t1; +Table Op Msg_type Msg_text +test.t1 check warning Size of datafile is: 14 Should be: 7 +test.t1 check error Record-count is not ok; is 2 Should be: 1 +test.t1 check warning Found 2 key parts. Should be: 1 +test.t1 check error Corrupt +# At this point we have a corrupt t1 +set autocommit = 0; +select * from t2; +a +1 +# Without fix select from t1 will break the transaction. After the fix +# transaction should be active and should hold lock on table t2. Alter +# table from con2 will wait only if the transaction is not broken. +select * from t1; +a +1 +4 +Warnings: +Error 145 Table './test/t1' is marked as crashed and should be repaired +Error 1194 Table 't1' is marked as crashed and should be repaired +Error 1034 Number of rows changed from 1 to 2 +ALTER TABLE t2 ADD val INT; +# With fix we should have alter table waiting for t2 lock here. +ROLLBACK; +SET autocommit = 1; +# Cleanup +drop table t1, t2; diff --git a/mysql-test/suite/ndb/r/ndb_restore_discover.result b/mysql-test/suite/ndb/r/ndb_restore_discover.result new file mode 100644 index 0000000000000..de10af870479e --- /dev/null +++ b/mysql-test/suite/ndb/r/ndb_restore_discover.result @@ -0,0 +1,33 @@ +# +# 18075170 - sql node restart required to avoid deadlock after +# restore +# +CREATE TABLE t1 (id INT) ENGINE=NDBCluster; +CREATE TABLE t2 (id INT) ENGINE=NDBCluster; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +DROP TABLE t1; +DROP TABLE t2; +SET autocommit = 0; +SELECT * FROM t1; +id +1 +SELECT * FROM t2; +id +1 +ROLLBACK; +SET autocommit = 1; +drop table t1; +drop table t2; +SET autocommit = 0; +SELECT * FROM t1; +id +1 +SELECT * FROM t2; +id +1 +ALTER TABLE t1 ADD val INT; +ROLLBACK; +SET autocommit = 1; +drop table t1; +drop table t2; diff --git a/mysql-test/suite/ndb/t/ndb_restore_discover.test b/mysql-test/suite/ndb/t/ndb_restore_discover.test new file mode 100644 index 0000000000000..6631c74d5c809 --- /dev/null +++ b/mysql-test/suite/ndb/t/ndb_restore_discover.test @@ -0,0 +1,70 @@ +-- source include/have_ndb.inc +-- source include/count_sessions.inc + +--echo # +--echo # 18075170 - sql node restart required to avoid deadlock after +--echo # restore +--echo # +# Test Auto Discover option within a transaction +# and make sure the transaction is not broken. +CREATE TABLE t1 (id INT) ENGINE=NDBCluster; +CREATE TABLE t2 (id INT) ENGINE=NDBCluster; + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); + +-- source include/ndb_backup.inc + +DROP TABLE t1; +DROP TABLE t2; + +-- source include/ndb_restore_master.inc + +SET autocommit = 0; +SELECT * FROM t1; + +# Without fix below select was resulting in DEADLOCK error. With fix select +# should succeed. +SELECT * FROM t2; +ROLLBACK; +SET autocommit = 1; + +drop table t1; +drop table t2; + +# +# Checking lock preservation in transaction +# +# Using existing backup to create the scenario. Tables are deleted as part of +# above test cleanup. Thus restoring the backup will bring the system to +# required state. +-- source include/ndb_restore_master.inc + +SET autocommit = 0; +SELECT * FROM t1; +SELECT * FROM t2; + +connect(con2, localhost, root); +--SEND ALTER TABLE t1 ADD val INT + +connection default; +# Alter from con2 will be in waiting state as there is a lock on t1 from +# default connection due to active transaction. We check for this condition +# then releasing the lock by rollbacking active transaction. +let $wait_condition= + SELECT count(*) = 1 FROM information_schema.processlist WHERE state + LIKE "Waiting%" AND info = "ALTER TABLE t1 ADD val INT"; +--source include/wait_condition.inc +ROLLBACK; +SET autocommit = 1; + +connection con2; +--REAP + +disconnect con2; +connection default; +drop table t1; +drop table t2; + +# Wait till all disconnects are completed +-- source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/merge_recover-master.opt b/mysql-test/t/myisam_recover-master.opt similarity index 100% rename from mysql-test/t/merge_recover-master.opt rename to mysql-test/t/myisam_recover-master.opt diff --git a/mysql-test/t/merge_recover.test b/mysql-test/t/myisam_recover.test similarity index 62% rename from mysql-test/t/merge_recover.test rename to mysql-test/t/myisam_recover.test index f2cb204eeb669..75aa9459acbac 100644 --- a/mysql-test/t/merge_recover.test +++ b/mysql-test/t/myisam_recover.test @@ -1,5 +1,9 @@ +--source include/count_sessions.inc + +--echo # +--echo # Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted +--echo # children.. --echo # ---echo # Test of MyISAM MRG tables with corrupted children. --echo # Run with --myisam-recover=force option. --echo # --echo # Preparation: we need to make sure that the merge parent @@ -57,10 +61,10 @@ eval $lock; --echo # connection default; --echo # ---echo # We have to disable the ps-protocol, to avoid +--echo # We have to disable the ps-protocol, to avoid --echo # "Prepared statement needs to be re-prepared" errors --echo # -- table def versions change all the time with full table cache. ---echo # +--echo # --disable_ps_protocol --disable_warnings drop table if exists t1, t1_mrg, t1_copy; @@ -69,12 +73,12 @@ let $MYSQLD_DATADIR=`select @@datadir`; --echo # --echo # Prepare a MERGE engine table, that refers to a corrupted --echo # child. ---echo # +--echo # create table t1 (a int, key(a)) engine=myisam; create table t1_mrg (a int) union (t1) engine=merge; --echo # --echo # Create a table with a corrupted index file: ---echo # save an old index file, insert more rows, +--echo # save an old index file, insert more rows, --echo # overwrite the new index file with the old one. --echo # insert into t1 (a) values (1), (2), (3); @@ -111,3 +115,64 @@ set @@global.table_open_cache=default; disconnect con1; connection default; --enable_ps_protocol + +--echo # +--echo # 18075170 - sql node restart required to avoid deadlock after +--echo # restore +--echo # +--echo # Check that auto-repair for MyISAM tables can now happen in the +--echo # middle of transaction, without aborting it. + +connection default; + +create table t1 (a int, key(a)) engine=myisam; +create table t2 (a int); +insert into t2 values (1); + +--echo # Create a table with a corrupted index file: +--echo # save an old index file, insert more rows, +--echo # overwrite the new index file with the old one. +insert into t1 (a) values (1); +flush table t1; +--copy_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/t1_copy.MYI +insert into t1 (a) values (4); +flush table t1; +--remove_file $MYSQLD_DATADIR/test/t1.MYI +--copy_file $MYSQLD_DATADIR/test/t1_copy.MYI $MYSQLD_DATADIR/test/t1.MYI +--remove_file $MYSQLD_DATADIR/test/t1_copy.MYI + +--echo # Check table is needed to mark the table as crashed. +check table t1; + +--echo # At this point we have a corrupt t1 +set autocommit = 0; +select * from t2; +--echo # Without fix select from t1 will break the transaction. After the fix +--echo # transaction should be active and should hold lock on table t2. Alter +--echo # table from con2 will wait only if the transaction is not broken. +select * from t1; + +connect(con2, localhost, root); +--SEND ALTER TABLE t2 ADD val INT + +connection default; +--echo # With fix we should have alter table waiting for t2 lock here. +let $wait_condition= + SELECT count(*) = 1 FROM information_schema.processlist WHERE state + LIKE "Waiting%" AND info = "ALTER TABLE t2 ADD val INT"; + +--source include/wait_condition.inc +ROLLBACK; +SET autocommit = 1; + +connection con2; +--REAP + +connection default; +disconnect con2; + +--echo # Cleanup +drop table t1, t2; + +# Wait till all disconnects are completed +-- source include/wait_until_count_sessions.inc diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f7405fb63b82c..0b2569742583c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3972,10 +3972,11 @@ request_backoff_action(enum_open_table_action action_arg, * We met a broken table that needs repair, or a table that is not present on this MySQL server and needs re-discovery. To perform the action, we need an exclusive metadata lock on - the table. Acquiring an X lock while holding other shared - locks is very deadlock-prone. If this is a multi- statement - transaction that holds metadata locks for completed - statements, we don't do it, and report an error instead. + the table. Acquiring X lock while holding other shared + locks can easily lead to deadlocks. We rely on MDL deadlock + detector to discover them. If this is a multi-statement + transaction that holds metadata locks for completed statements, + we should keep these locks after discovery/repair. The action type in this case is OT_DISCOVER or OT_REPAIR. * Our attempt to acquire an MDL lock lead to a deadlock, detected by the MDL deadlock detector. The current @@ -4016,7 +4017,7 @@ request_backoff_action(enum_open_table_action action_arg, keep tables open between statements and a livelock is not possible. */ - if (action_arg != OT_REOPEN_TABLES && m_has_locks) + if (action_arg == OT_BACKOFF_AND_RETRY && m_has_locks) { my_error(ER_LOCK_DEADLOCK, MYF(0)); m_thd->mark_transaction_to_rollback(true); @@ -4043,6 +4044,32 @@ request_backoff_action(enum_open_table_action action_arg, } +/** + An error handler to mark transaction to rollback on DEADLOCK error + during DISCOVER / REPAIR. +*/ +class MDL_deadlock_discovery_repair_handler : public Internal_error_handler +{ +public: + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) + { + if (sql_errno == ER_LOCK_DEADLOCK) + { + thd->mark_transaction_to_rollback(true); + } + /* + We have marked this transaction to rollback. Return false to allow + error to be reported or handled by other handlers. + */ + return false; + } +}; + /** Recover from failed attempt of open table by performing requested action. @@ -4058,6 +4085,12 @@ Open_table_context:: recover_from_failed_open() { bool result= FALSE; + MDL_deadlock_discovery_repair_handler handler; + /* + Install error handler to mark transaction to rollback on DEADLOCK error. + */ + m_thd->push_internal_handler(&handler); + /* Execute the action. */ switch (m_action) { @@ -4079,7 +4112,12 @@ recover_from_failed_open() m_thd->warning_info->clear_warning_info(m_thd->query_id); m_thd->clear_error(); // Clear error message - m_thd->mdl_context.release_transactional_locks(); + /* + Rollback to start of the current statement to release exclusive lock + on table which was discovered but preserve locks from previous statements + in current transaction. + */ + m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp()); break; } case OT_REPAIR: @@ -4093,12 +4131,18 @@ recover_from_failed_open() m_failed_table->table_name, FALSE); result= auto_repair_table(m_thd, m_failed_table); - m_thd->mdl_context.release_transactional_locks(); + /* + Rollback to start of the current statement to release exclusive lock + on table which was discovered but preserve locks from previous statements + in current transaction. + */ + m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp()); break; } default: DBUG_ASSERT(0); } + m_thd->pop_internal_handler(); /* Reset the pointers to conflicting MDL request and the TABLE_LIST element, set when we need auto-discovery or repair, From 820bf7b1f17fbaedb1061c7c845e755e6ebc1572 Mon Sep 17 00:00:00 2001 From: Ajo Robert Date: Tue, 12 May 2015 20:27:26 +0530 Subject: [PATCH 04/47] Bug #18075170 SQL NODE RESTART REQUIRED TO AVOID DEADLOCK AFTER RESTORE Test Failure Fix. --- mysql-test/r/myisam_recover.result | 2 +- mysql-test/t/myisam_recover.test | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/myisam_recover.result b/mysql-test/r/myisam_recover.result index 3c8639e0518a4..0829c1e8b82da 100644 --- a/mysql-test/r/myisam_recover.result +++ b/mysql-test/r/myisam_recover.result @@ -139,7 +139,7 @@ a 1 4 Warnings: -Error 145 Table './test/t1' is marked as crashed and should be repaired +Error 145 Table 't1' is marked as crashed and should be repaired Error 1194 Table 't1' is marked as crashed and should be repaired Error 1034 Number of rows changed from 1 to 2 ALTER TABLE t2 ADD val INT; diff --git a/mysql-test/t/myisam_recover.test b/mysql-test/t/myisam_recover.test index 75aa9459acbac..335c5e34bf0ee 100644 --- a/mysql-test/t/myisam_recover.test +++ b/mysql-test/t/myisam_recover.test @@ -124,6 +124,7 @@ connection default; --echo # middle of transaction, without aborting it. connection default; +--let $MYSQL_DATA_DIR=`select @@datadir` create table t1 (a int, key(a)) engine=myisam; create table t2 (a int); @@ -150,6 +151,7 @@ select * from t2; --echo # Without fix select from t1 will break the transaction. After the fix --echo # transaction should be active and should hold lock on table t2. Alter --echo # table from con2 will wait only if the transaction is not broken. +--replace_result $MYSQL_DATA_DIR '' ./ '' test/ '' select * from t1; connect(con2, localhost, root); From dc45e408250c582eb532417a42cef5b5a8e2fe77 Mon Sep 17 00:00:00 2001 From: Tatiana Azundris Nuernberg Date: Mon, 18 May 2015 08:09:02 +0100 Subject: [PATCH 05/47] Bug#20642505: HENRY SPENCER REGULAR EXPRESSIONS (REGEX) LIBRARY The MySQL server uses Henry Spencer's library for regular expressions to support the REGEXP/RLIKE string operator. This changeset adapts a recent fix from the upstream for better 32-bit compatiblity. (Note that we cannot simply use the current upstream version as a drop-in replacement for the version used by the server as the latter has been extended to understand MySQL charsets etc.) --- regex/regcomp.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/regex/regcomp.c b/regex/regcomp.c index abc18174f5653..b1074a1d79ccd 100644 --- a/regex/regcomp.c +++ b/regex/regcomp.c @@ -1,3 +1,11 @@ +/* Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved. + See file COPYRIGHT for details. + + This file was modified by Oracle on 2015-05-18 for 32-bit compatibility. + + Modifications copyright (c) 2015, Oracle and/or its affiliates. All rights + reserved. */ + #include #include #include @@ -133,12 +141,26 @@ CHARSET_INFO *charset; } else len = strlen((char *)pattern); + /* + Find the maximum len we can safely process + without a rollover and a mis-malloc. + p->ssize is a sopno is a long (32+ bit signed); + size_t is 16+ bit unsigned. + */ + { + size_t new_ssize = len / (size_t)2 * (size_t)3 + (size_t)1; /* ugh */ + if ((new_ssize < len) || /* size_t rolled over */ + ((SIZE_T_MAX / sizeof(sop)) < new_ssize) || /* malloc arg */ + (new_ssize > LONG_MAX)) /* won't fit in ssize */ + return(REG_ESPACE); /* MY_REG_ESPACE or MY_REG_INVARG */ + p->ssize = new_ssize; + } + /* do the mallocs early so failure handling is easy */ g = (struct re_guts *)malloc(sizeof(struct re_guts) + (NC-1)*sizeof(cat_t)); if (g == NULL) return(REG_ESPACE); - p->ssize = (long) (len/(size_t)2*(size_t)3 + (size_t)1); /* ugh */ p->strip = (sop *)malloc(p->ssize * sizeof(sop)); p->slen = 0; if (p->strip == NULL) { From b4daac21f52ced96c11632b83445111c0acede56 Mon Sep 17 00:00:00 2001 From: Bin Su Date: Thu, 21 May 2015 11:52:17 +0800 Subject: [PATCH 06/47] Bug#21113036 - MYSQL/INNODB MIX BUFFERED AND DIRECT IO As man page of open(2) suggested, we should open the same file in the same mode, to have better performance. For some data files, we will first call os_file_create_simple_no_error_handling_func() to open them, and then call os_file_create_func() again. We have to make sure if DIRECT IO is specified, these two functions should both open file with O_DIRECT. Reviewed-by: Sunny Bains RB: 8981 --- storage/innobase/os/os0file.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index 6c7f4a25bedf0..e09c62365226f 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -1,6 +1,6 @@ /*********************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted @@ -1276,16 +1276,19 @@ os_file_create_simple_no_error_handling_func( #else /* __WIN__ */ os_file_t file; int create_flag; + const char* mode_str = NULL; ut_a(name); if (create_mode == OS_FILE_OPEN) { + mode_str = "OPEN"; if (access_type == OS_FILE_READ_ONLY) { create_flag = O_RDONLY; } else { create_flag = O_RDWR; } } else if (create_mode == OS_FILE_CREATE) { + mode_str = "CREATE"; create_flag = O_RDWR | O_CREAT | O_EXCL; } else { create_flag = 0; @@ -1310,6 +1313,14 @@ os_file_create_simple_no_error_handling_func( #endif } else { *success = TRUE; + + /* This function is always called for data files, we should + disable OS caching (O_DIRECT) here as we do in + os_file_create_func(), so we open the same file in the same + mode, see man page of open(2). */ + if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) { + os_file_set_nocache(file, name, mode_str); + } } return(file); From 42fab527a7d5d8317035456ef12258e868d2389d Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Tue, 10 Jun 2014 10:57:30 -0600 Subject: [PATCH 07/47] From c0055f0d41af73f0d8a59ccb66fc7a3a43acdeaa Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Fri, 29 May 2015 09:28:53 +0200 Subject: [PATCH 08/47] Raise version number after tagging 5.1.75 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 492821b0b5787..84ffbb7ac7406 100644 --- a/configure.in +++ b/configure.in @@ -29,7 +29,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.75], [], [mysql]) +AC_INIT([MySQL Server], [5.1.76], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 4b8304a9a41c8382d18e084608c33e5c27bec311 Mon Sep 17 00:00:00 2001 From: Debarun Banerjee Date: Wed, 3 Jun 2015 11:27:38 +0530 Subject: [PATCH 09/47] BUG#21126772 VALGRIND FAILURE IN ENGINES/FUNCS SUITE Problem : --------- This is a regression of bug-19138298. During purge, if btr_pcur_restore_position fails, we set found_clust to FALSE so that it can find a possible clustered index record in future calls for the same undo entry. This, however, overwrites the old_rec_buf while initializing pcur again in next call. The leak is reproducible in local environment and with the test provided along with bug-19138298. Solution : ---------- If btr_pcur_restore_position() fails close the cursor. Reviewed-by: Marko Makela Reviewed-by: Annamalai Gurusami RB: 9074 --- storage/innobase/row/row0purge.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index bfda1a47d0acf..e32f81b4da9ba 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -80,7 +80,7 @@ row_purge_node_create( /***********************************************************//** Repositions the pcur in the purge node on the clustered index record, -if found. +if found. If the record is not found, close pcur. @return TRUE if the record was found */ static ibool @@ -106,6 +106,11 @@ row_purge_reposition_pcur( } } + /* Close the current cursor if we fail to position it correctly. */ + if (!node->found_clust) { + btr_pcur_close(&node->pcur); + } + return(node->found_clust); } @@ -143,8 +148,8 @@ row_purge_remove_clust_if_poss_low( if (!success) { /* The record is already removed */ - - btr_pcur_commit_specify_mtr(pcur, &mtr); + /* Persistent cursor is closed if reposition fails. */ + mtr_commit(&mtr); return(TRUE); } @@ -258,7 +263,12 @@ row_purge_poss_sec( btr_pcur_get_rec(&node->pcur), &mtr, index, entry); - btr_pcur_commit_specify_mtr(&node->pcur, &mtr); + /* Persistent cursor is closed if reposition fails. */ + if (node->found_clust) { + btr_pcur_commit_specify_mtr(&node->pcur, &mtr); + } else { + mtr_commit(&mtr); + } return(can_delete); } From e59914034ab695035c3fe48f046a96bb98d53044 Mon Sep 17 00:00:00 2001 From: Debarun Banerjee Date: Wed, 3 Jun 2015 11:43:12 +0530 Subject: [PATCH 10/47] BUG#21065746 RQG_PARTN_PRUNING_VALGRIND FAILED IN REM0REC.CC Problem : --------- This is a regression of Bug#19138298. In purge_node_t::validate_pcur we are trying to get offsets for all columns of clustered index from stored record in persistent cursor. This would fail when stored record is not having all fields of the index. The stored record stores only fields that are needed to uniquely identify the entry. Solution : ---------- 1. Use pcur.old_n_fields to get fields that are stored 2. Add comment to note dependency between stored fields in purge node ref and stored cursor. 3. Return if the cursor record is not already stored as it is not safe to access cursor record directly without latch. Reviewed-by: Marko Makela RB: 9139 --- storage/innobase/row/row0purge.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index e32f81b4da9ba..5e6e6b4ca41aa 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -823,12 +823,12 @@ Validate the persisent cursor in the purge node. The purge node has two references to the clustered index record - one via the ref member, and the other via the persistent cursor. These two references must match each other if the found_clust flag is set. -@return true if the persistent cursor is consistent with the ref member.*/ +@return true if the stored copy of persistent cursor is consistent +with the ref member.*/ ibool row_purge_validate_pcur( purge_node_t* node) { - const rec_t* rec ; dict_index_t* clust_index; ulint* offsets; int st; @@ -841,23 +841,25 @@ row_purge_validate_pcur( return(TRUE); } - clust_index = node->pcur.btr_cur.index; - - if (node->pcur.old_stored == BTR_PCUR_OLD_STORED) { - rec = node->pcur.old_rec; - } else { - rec = btr_pcur_get_rec(&node->pcur); + if (node->pcur.old_stored != BTR_PCUR_OLD_STORED) { + return(TRUE); } - offsets = rec_get_offsets(rec, - clust_index, NULL, ULINT_UNDEFINED, &node->heap); + clust_index = node->pcur.btr_cur.index; + + offsets = rec_get_offsets(node->pcur.old_rec, clust_index, NULL, + node->pcur.old_n_fields, &node->heap); - st = cmp_dtuple_rec(node->ref, rec, offsets); + /* Here we are comparing the purge ref record and the stored initial + part in persistent cursor. Both cases we store n_uniq fields of the + cluster index and so it is fine to do the comparison. We note this + dependency here as pcur and ref belong to different modules. */ + st = cmp_dtuple_rec(node->ref, node->pcur.old_rec, offsets); if (st != 0) { fprintf(stderr, "Purge node pcur validation failed\n"); dtuple_print(stderr, node->ref); - rec_print(stderr, rec, clust_index); + rec_print(stderr, node->pcur.old_rec, clust_index); return(FALSE); } From 044e3b1d07c0854c39178d3054ab0cd0a3188436 Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Thu, 4 Jun 2015 11:53:17 +0530 Subject: [PATCH 11/47] Bug #20605441 : BUFFER OVERFLOW IN MYSQLSLAP Description:- mysqlslap is a diagnostic utility designed to emulate client load for a MySQL server and to report the timing of each stage. This utility crashes when invalid values are passed to the options 'num_int_cols_opt' or 'num_chars_cols_opt' or 'engine'. Analysis:- mysqlslap uses "parse_option()" to parse the values specified to the options 'num_int_cols_opt', 'num_chars_cols_opt' and 'engine'. These options takes values separated by commas. In "parse_option()", the comma separated values are separated and copied into a buffer without checking the length of the string to be copied. The size of the buffer is defined by a macro HUGE_STRING_LENGTH whose value is 8196. So if the length of the any of the comma separated value exceeds HUGE_STRING_LENGTH, will result in a buffer overflow. Fix:- A check is introduced in "parse_option()" to check whether the size of the string to be copied is more than HUGE_STRING_LENGTH. If it is more, an error, "Invalid value specified for the option 'xxx'" is thrown. Option length was incorrectly calculated for the last comma separated value. So fixed that as well. --- client/mysqlslap.c | 48 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/client/mysqlslap.c b/client/mysqlslap.c index 4c4dbafc24d45..65c5945e60376 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -245,7 +245,7 @@ void print_conclusions_csv(conclusions *con); void generate_stats(conclusions *con, option_string *eng, stats *sptr); uint parse_comma(const char *string, uint **range); uint parse_delimiter(const char *script, statement **stmt, char delm); -uint parse_option(const char *origin, option_string **stmt, char delm); +int parse_option(const char *origin, option_string **stmt, char delm); static int drop_schema(MYSQL *mysql, const char *db); uint get_random_string(char *buf); static statement *build_table_string(void); @@ -1227,7 +1227,13 @@ get_options(int *argc,char ***argv) if (num_int_cols_opt) { option_string *str; - parse_option(num_int_cols_opt, &str, ','); + if(parse_option(num_int_cols_opt, &str, ',') == -1) + { + fprintf(stderr, "Invalid value specified for the option " + "'number-int-cols'\n"); + option_cleanup(str); + return 1; + } num_int_cols= atoi(str->string); if (str->option) num_int_cols_index= atoi(str->option); @@ -1237,7 +1243,13 @@ get_options(int *argc,char ***argv) if (num_char_cols_opt) { option_string *str; - parse_option(num_char_cols_opt, &str, ','); + if(parse_option(num_char_cols_opt, &str, ',') == -1) + { + fprintf(stderr, "Invalid value specified for the option " + "'number-char-cols'\n"); + option_cleanup(str); + return 1; + } num_char_cols= atoi(str->string); if (str->option) num_char_cols_index= atoi(str->option); @@ -1473,7 +1485,13 @@ get_options(int *argc,char ***argv) printf("Parsing engines to use.\n"); if (default_engine) - parse_option(default_engine, &engine_options, ','); + { + if(parse_option(default_engine, &engine_options, ',') == -1) + { + fprintf(stderr, "Invalid value specified for the option 'engine'\n"); + return 1; + } + } if (tty_password) opt_password= get_tty_password(NullS); @@ -1946,7 +1964,7 @@ pthread_handler_t run_task(void *p) DBUG_RETURN(0); } -uint +int parse_option(const char *origin, option_string **stmt, char delm) { char *retstr; @@ -1966,6 +1984,13 @@ parse_option(const char *origin, option_string **stmt, char delm) char buffer[HUGE_STRING_LENGTH]; char *buffer_ptr; + /* + Return an error if the length of the any of the comma seprated value + exceeds HUGE_STRING_LENGTH. + */ + if ((size_t)(retstr - ptr) > HUGE_STRING_LENGTH) + return -1; + count++; strncpy(buffer, ptr, (size_t)(retstr - ptr)); if ((buffer_ptr= strchr(buffer, ':'))) @@ -1998,6 +2023,13 @@ parse_option(const char *origin, option_string **stmt, char delm) { char *origin_ptr; + /* + Return an error if the length of the any of the comma seprated value + exceeds HUGE_STRING_LENGTH. + */ + if (strlen(ptr) > HUGE_STRING_LENGTH) + return -1; + if ((origin_ptr= strchr(ptr, ':'))) { char *option_ptr; @@ -2008,13 +2040,13 @@ parse_option(const char *origin, option_string **stmt, char delm) option_ptr= (char *)ptr + 1 + tmp->length; /* Move past the : and the first string */ - tmp->option_length= (size_t)((ptr + length) - option_ptr); + tmp->option_length= strlen(option_ptr); tmp->option= my_strndup(option_ptr, tmp->option_length, MYF(MY_FAE)); } else { - tmp->length= (size_t)((ptr + length) - ptr); + tmp->length= strlen(ptr); tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE)); } From e070d1fc80d2c710902782429b52ebfe4407d11b Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Fri, 5 Jun 2015 10:44:33 +0530 Subject: [PATCH 12/47] From 7c98e8a31b48c76a519eeff802d29ad9a8f7b1fc Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 11 Jun 2015 16:43:56 +0200 Subject: [PATCH 13/47] fix after the tokudb ft-index merge --- {util => storage/tokudb/ft-index/util}/tests/sm-basic.cc | 0 .../tokudb/ft-index/util}/tests/sm-crash-double-free.cc | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {util => storage/tokudb/ft-index/util}/tests/sm-basic.cc (100%) rename {util => storage/tokudb/ft-index/util}/tests/sm-crash-double-free.cc (100%) diff --git a/util/tests/sm-basic.cc b/storage/tokudb/ft-index/util/tests/sm-basic.cc similarity index 100% rename from util/tests/sm-basic.cc rename to storage/tokudb/ft-index/util/tests/sm-basic.cc diff --git a/util/tests/sm-crash-double-free.cc b/storage/tokudb/ft-index/util/tests/sm-crash-double-free.cc similarity index 100% rename from util/tests/sm-crash-double-free.cc rename to storage/tokudb/ft-index/util/tests/sm-crash-double-free.cc From b96c196f1cd5d77e524cbf952539bdd33c65ffc1 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 11 Jun 2015 16:48:10 +0200 Subject: [PATCH 14/47] Item_cache::safe_charset_converter() fixes * take into account that example may be NULL * use example->safe_charset_converter(), copy-paste from Item::safe_charset_converter() (example might have its own implementation) * handle the case when the charset doesn't need conversion (and return this). --- sql/item.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index f8d1c85f44752..dbcf1b4cbe114 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1146,18 +1146,24 @@ Item *Item::safe_charset_converter(CHARSET_INFO *tocs) because Item_singlerow_subselect later calls Item_cache-specific methods, e.g. row[i]->store() and row[i]->cache_value(). - Let's wrap Item_func_conv_charset to a new Item_cache, + Let's wrap Item_func_conv_charset in a new Item_cache, so the Item_cache-specific methods can still be used for Item_singlerow_subselect::row[i] safely. + As a bonus we cache the converted value, instead of converting every time + TODO: we should eventually check all other use cases of change_item_tree(). Perhaps some more potentially dangerous substitution examples exist. */ Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs) { - Item_func_conv_charset *conv= new Item_func_conv_charset(example, tocs, 1); + if (!example) + return Item::safe_charset_converter(tocs); + Item *conv= example->safe_charset_converter(tocs); + if (conv == example) + return this; Item_cache *cache; - if (!conv || !conv->safe || !(cache= new Item_cache_str(conv))) + if (!conv || !(cache= new Item_cache_str(conv))) return NULL; // Safe conversion is not possible, or OEM cache->setup(conv); cache->fixed= false; // Make Item::fix_fields() happy From d199a0ffb0aac86881ea2db7dd78bc07b438dc67 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 11 Jun 2015 17:47:52 +0200 Subject: [PATCH 15/47] more renames after tokudb merge --- .../tokudb/mysql-test/tokudb_bugs}/r/db805.result | 0 .../tokudb/mysql-test/tokudb_bugs}/r/db806.result | 0 .../tokudb/mysql-test/tokudb_bugs}/r/db811.result | 0 .../tokudb/mysql-test/tokudb_bugs}/r/db811s.result | 0 .../tokudb/mysql-test/tokudb_bugs}/r/db823.result | 0 .../tokudb/mysql-test/tokudb_bugs}/t/db805.test | 0 .../tokudb/mysql-test/tokudb_bugs}/t/db806.test | 0 .../tokudb/mysql-test/tokudb_bugs}/t/db811.test | 0 .../tokudb/mysql-test/tokudb_bugs}/t/db811s.test | 0 .../tokudb/mysql-test/tokudb_bugs}/t/db823.test | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/r/db805.result (100%) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/r/db806.result (100%) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/r/db811.result (100%) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/r/db811s.result (100%) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/r/db823.result (100%) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/t/db805.test (100%) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/t/db806.test (100%) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/t/db811.test (100%) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/t/db811s.test (100%) rename {mysql-test/suite/tokudb.bugs => storage/tokudb/mysql-test/tokudb_bugs}/t/db823.test (100%) diff --git a/mysql-test/suite/tokudb.bugs/r/db805.result b/storage/tokudb/mysql-test/tokudb_bugs/r/db805.result similarity index 100% rename from mysql-test/suite/tokudb.bugs/r/db805.result rename to storage/tokudb/mysql-test/tokudb_bugs/r/db805.result diff --git a/mysql-test/suite/tokudb.bugs/r/db806.result b/storage/tokudb/mysql-test/tokudb_bugs/r/db806.result similarity index 100% rename from mysql-test/suite/tokudb.bugs/r/db806.result rename to storage/tokudb/mysql-test/tokudb_bugs/r/db806.result diff --git a/mysql-test/suite/tokudb.bugs/r/db811.result b/storage/tokudb/mysql-test/tokudb_bugs/r/db811.result similarity index 100% rename from mysql-test/suite/tokudb.bugs/r/db811.result rename to storage/tokudb/mysql-test/tokudb_bugs/r/db811.result diff --git a/mysql-test/suite/tokudb.bugs/r/db811s.result b/storage/tokudb/mysql-test/tokudb_bugs/r/db811s.result similarity index 100% rename from mysql-test/suite/tokudb.bugs/r/db811s.result rename to storage/tokudb/mysql-test/tokudb_bugs/r/db811s.result diff --git a/mysql-test/suite/tokudb.bugs/r/db823.result b/storage/tokudb/mysql-test/tokudb_bugs/r/db823.result similarity index 100% rename from mysql-test/suite/tokudb.bugs/r/db823.result rename to storage/tokudb/mysql-test/tokudb_bugs/r/db823.result diff --git a/mysql-test/suite/tokudb.bugs/t/db805.test b/storage/tokudb/mysql-test/tokudb_bugs/t/db805.test similarity index 100% rename from mysql-test/suite/tokudb.bugs/t/db805.test rename to storage/tokudb/mysql-test/tokudb_bugs/t/db805.test diff --git a/mysql-test/suite/tokudb.bugs/t/db806.test b/storage/tokudb/mysql-test/tokudb_bugs/t/db806.test similarity index 100% rename from mysql-test/suite/tokudb.bugs/t/db806.test rename to storage/tokudb/mysql-test/tokudb_bugs/t/db806.test diff --git a/mysql-test/suite/tokudb.bugs/t/db811.test b/storage/tokudb/mysql-test/tokudb_bugs/t/db811.test similarity index 100% rename from mysql-test/suite/tokudb.bugs/t/db811.test rename to storage/tokudb/mysql-test/tokudb_bugs/t/db811.test diff --git a/mysql-test/suite/tokudb.bugs/t/db811s.test b/storage/tokudb/mysql-test/tokudb_bugs/t/db811s.test similarity index 100% rename from mysql-test/suite/tokudb.bugs/t/db811s.test rename to storage/tokudb/mysql-test/tokudb_bugs/t/db811s.test diff --git a/mysql-test/suite/tokudb.bugs/t/db823.test b/storage/tokudb/mysql-test/tokudb_bugs/t/db823.test similarity index 100% rename from mysql-test/suite/tokudb.bugs/t/db823.test rename to storage/tokudb/mysql-test/tokudb_bugs/t/db823.test From cbf9494e385403171160bc0f81570c1837c7f820 Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Tue, 16 Jun 2015 12:08:42 +0200 Subject: [PATCH 16/47] Add packaging scripts for docker builds --- packaging/rpm-docker/CMakeLists.txt | 29 + packaging/rpm-docker/my.cnf | 30 + packaging/rpm-docker/mysql.spec.in | 1158 +++++++++++++++++++++++++++ 3 files changed, 1217 insertions(+) create mode 100644 packaging/rpm-docker/CMakeLists.txt create mode 100644 packaging/rpm-docker/my.cnf create mode 100644 packaging/rpm-docker/mysql.spec.in diff --git a/packaging/rpm-docker/CMakeLists.txt b/packaging/rpm-docker/CMakeLists.txt new file mode 100644 index 0000000000000..980cb2b4dcbf0 --- /dev/null +++ b/packaging/rpm-docker/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +IF(UNIX) + SET(prefix ${CMAKE_INSTALL_PREFIX}) + + SET(SPECFILENAME "mysql.spec") + + # Left in current directory, to be taken during build + CONFIGURE_FILE(mysql.spec.in ${CMAKE_CURRENT_BINARY_DIR}/${SPECFILENAME} @ONLY) + + FOREACH(fedfile my.cnf) + CONFIGURE_FILE(${fedfile} ${CMAKE_CURRENT_BINARY_DIR}/${fedfile} COPYONLY) + ENDFOREACH() +ENDIF() + diff --git a/packaging/rpm-docker/my.cnf b/packaging/rpm-docker/my.cnf new file mode 100644 index 0000000000000..8951b27d7768e --- /dev/null +++ b/packaging/rpm-docker/my.cnf @@ -0,0 +1,30 @@ +# For advice on how to change settings please see +# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html + +[mysqld] +# +# Remove leading # and set to the amount of RAM for the most important data +# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%. +# innodb_buffer_pool_size = 128M +# +# Remove leading # to turn on a very important data integrity option: logging +# changes to the binary log between backups. +# log_bin +# +# Remove leading # to set options mainly useful for reporting servers. +# The server defaults are faster for transactions and fast SELECTs. +# Adjust sizes as needed, experiment to find the optimal values. +# join_buffer_size = 128M +# sort_buffer_size = 2M +# read_rnd_buffer_size = 2M +datadir=/var/lib/mysql +socket=/var/lib/mysql/mysql.sock +secure-file-priv=/var/lib/mysql-files +user=mysql + +# Disabling symbolic-links is recommended to prevent assorted security risks +symbolic-links=0 + +log-error=/var/log/mysqld.log +pid-file=/var/run/mysqld/mysqld.pid + diff --git a/packaging/rpm-docker/mysql.spec.in b/packaging/rpm-docker/mysql.spec.in new file mode 100644 index 0000000000000..c5f548ef896f8 --- /dev/null +++ b/packaging/rpm-docker/mysql.spec.in @@ -0,0 +1,1158 @@ +# Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston +# MA 02110-1301 USA. + +%global mysql_vendor Oracle and/or its affiliates +%global mysqldatadir /var/lib/mysql + +# Regression tests may take a long time, override the default to skip them +%{!?runselftest:%global runselftest 0} + +%{!?product_suffix: %global product_suffix community} +%{!?feature_set: %global feature_set community} +%{!?compilation_comment_release: %global compilation_comment_release MySQL Community Server - (GPL)} +%{!?compilation_comment_debug: %global compilation_comment_debug MySQL Community Server - Debug (GPL)} +%{!?src_base: %global src_base mysql} + +%global src_dir %{src_base}-%{version} + +%if 0%{?commercial} +%global license_files_server %{src_dir}/LICENSE.mysql +%global license_type Commercial +%else +%global license_files_server %{src_dir}/COPYING %{src_dir}/README +%global license_type GPLv2 +%endif + +Name: mysql-%{product_suffix} +Summary: A very fast and reliable SQL database server +Group: Applications/Databases +Version: @VERSION@ +Release: 2%{?commercial:.1}%{?dist} +License: Copyright (c) 2000, @MYSQL_COPYRIGHT_YEAR@, %{mysql_vendor}. All rights reserved. Under %{?license_type} license as shown in the Description field. +URL: http://www.mysql.com/ +Packager: MySQL Release Engineering +Vendor: %{mysql_vendor} +Source0: https://cdn.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/%{src_dir}.tar.gz +BuildRequires: cmake +BuildRequires: perl +BuildRequires: perl(Time::HiRes) +BuildRequires: perl(Env) +BuildRequires: time +BuildRequires: libaio-devel +BuildRequires: ncurses-devel +BuildRequires: openssl-devel +BuildRequires: zlib-devel +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) + +# For rpm => 4.9 only: https://fedoraproject.org/wiki/Packaging:AutoProvidesAndRequiresFiltering +%global __requires_exclude ^perl\\((GD|hostnames|lib::mtr|lib::v1|mtr_|My::) +%global __provides_exclude_from ^(/usr/share/(mysql|mysql-test)/.*|%{_libdir}/mysql/plugin/.*\\.so)$ + +%description +The MySQL(TM) software delivers a very fast, multi-threaded, multi-user, +and robust SQL (Structured Query Language) database server. MySQL Server +is intended for mission-critical, heavy-load production systems as well +as for embedding into mass-deployed software. MySQL is a trademark of +%{mysql_vendor} + +The MySQL software has Dual Licensing, which means you can use the MySQL +software free of charge under the GNU General Public License +(http://www.gnu.org/licenses/). You can also purchase commercial MySQL +licenses from %{mysql_vendor} if you do not wish to be bound by the terms of +the GPL. See the chapter "Licensing and Support" in the manual for +further info. + +The MySQL web site (http://www.mysql.com/) provides the latest +news and information about the MySQL software. Also please see the +documentation and the manual for more information. + +%package server-minimal +Summary: A very fast and reliable SQL database server +Group: Applications/Databases +Requires: shadow-utils +Provides: mysql-server = %{version}-%{release} +Provides: mysql-server%{?_isa} = %{version}-%{release} +Provides: mysql-compat-server = %{version}-%{release} +Provides: mysql-compat-server%{?_isa} = %{version}-%{release} + +%description server-minimal +The MySQL(TM) software delivers a very fast, multi-threaded, multi-user, +and robust SQL (Structured Query Language) database server. MySQL Server +is intended for mission-critical, heavy-load production systems as well +as for embedding into mass-deployed software. MySQL is a trademark of +%{mysql_vendor} + +The MySQL software has Dual Licensing, which means you can use the MySQL +software free of charge under the GNU General Public License +(http://www.gnu.org/licenses/). You can also purchase commercial MySQL +licenses from %{mysql_vendor} if you do not wish to be bound by the terms of +the GPL. See the chapter "Licensing and Support" in the manual for +further info. + +The MySQL web site (http://www.mysql.com/) provides the latest news and +information about the MySQL software. Also please see the documentation +and the manual for more information. + +This package includes the MySQL server binary as well as related utilities +to run and administer a MySQL server. +%prep +%setup -q -T -a 0 -c -n %{src_dir} + +%build +# Fail quickly and obviously if user tries to build as root +%if 0%{?runselftest} +if [ "x$(id -u)" = "x0" ] ; then + echo "The MySQL regression tests may fail if run as root." + echo "If you really need to build the RPM as root, use" + echo "--define='runselftest 0' to skip the regression tests." + exit 1 +fi +%endif + +# Build full release +mkdir release +( + cd release + cmake ../%{src_dir} \ + -DBUILD_CONFIG=mysql_release \ + -DINSTALL_LAYOUT=RPM \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_C_FLAGS="%{optflags}" \ + -DCMAKE_CXX_FLAGS="%{optflags}" \ + -DWITH_INNODB_MEMCACHED=1 \ + -DINSTALL_LIBDIR="%{_lib}/mysql" \ + -DINSTALL_PLUGINDIR="%{_lib}/mysql/plugin" \ + -DINSTALL_SQLBENCHDIR="" \ + -DINSTALL_MYSQLTESTDIR="" \ + -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \ + -DFEATURE_SET="%{feature_set}" \ + -DWITH_EMBEDDED_SERVER=0 \ + -DWITH_EMBEDDED_SHARED_LIBRARY=0 \ + -DWITH_SSL=system \ + -DCOMPILATION_COMMENT="%{compilation_comment_release}" \ + -DMYSQL_SERVER_SUFFIX="%{?server_suffix}" + echo BEGIN_NORMAL_CONFIG ; egrep '^#define' include/config.h ; echo END_NORMAL_CONFIG + make %{?_smp_mflags} VERBOSE=1 +) + +%install +MBD=$RPM_BUILD_DIR/%{src_dir} + +# Ensure that needed directories exists +install -d -m 0750 %{buildroot}/var/lib/mysql +install -d -m 0755 %{buildroot}/var/run/mysqld +install -d -m 0750 %{buildroot}/var/lib/mysql-files + +# Install all binaries +cd $MBD/release +make DESTDIR=%{buildroot} install + +# TODO: move to rpm-docker +install -D -m 0644 $MBD/release/packaging/rpm-docker/my.cnf %{buildroot}%{_sysconfdir}/my.cnf +install -d %{buildroot}%{_sysconfdir}/my.cnf.d + +# Remove man, sql-bench, include, and libs +for f in %{_mandir} %{_datadir}/sql-bench %{_includedir} %{_datadir}/aclocal/mysql.m4 ; do + rm -rf %{buildroot}$f +done +rm -rf %{buildroot}%{_libdir}/mysql/libmysql* + +# Removing some tools +for f in msql2mysql mysqlaccess mysqlaccess.conf mysqlbug mysql_convert_table_format \ + mysql_find_rows mysql_fix_extensions mysqlhotcopy mysql_setpermission \ + mysql_waitpid mysql_zap; do + rm -f %{buildroot}%{_bindir}/$f +done + +for f in innochecksum myisamchk myisam_ftdump myisamlog myisampack mysqladmin \ + mysqlbinlog mysqlcheck mysql_client_test mysql_config_editor \ + mysqld_multi mysqld_safe mysqldumpslow mysql_embedded mysqlimport \ + mysql_plugin mysql_secure_installation mysqlshow mysqlslap mysqltest \ + perror replace resolveip resolve_stack_dump; do + rm -f %{buildroot}%{_bindir}/$f +done + +# Remove test plugins +for p in auth.so auth_test_plugin.so daemon_example.ini libdaemon_example.so qa_auth_client.so \ + qa_auth_interface.so qa_auth_server.so replication_observers_example_plugin.so ha_example.so ; do + rm -f %{buildroot}%{_libdir}/mysql/plugin/$p +done + +# No need for these scripts +rm -f %{buildroot}%{_datadir}/mysql/{mysql.server,mysqld_multi.server,mysql-log-rotate,binary-configure} +rm -f %{buildroot}%{_datadir}/mysql/{*.ini,*.cnf} + +%check +%if 0%{?runselftest} +pushd release +make test VERBOSE=1 +export MTR_BUILD_THREAD=auto +pushd mysql-test +./mtr \ + --mem --parallel=auto --force --retry=0 \ + --mysqld=--binlog-format=mixed \ + --suite-timeout=720 --testcase-timeout=30 \ + --clean-vardir +rm -r $(readlink var) var +%endif + +%pre server-minimal +/usr/sbin/groupadd -g 27 -o -r mysql >/dev/null 2>&1 || : +/usr/sbin/useradd -M -N -g mysql -o -r -d /var/lib/mysql -s /bin/false \ + -c "MySQL Server" -u 27 mysql >/dev/null 2>&1 || : + +%post server-minimal +/bin/touch /var/log/mysqld.log >/dev/null 2>&1 || : +/bin/chmod 0640 /var/log/mysqld.log >/dev/null 2>&1 || : +/bin/chown mysql:mysql /var/log/mysqld.log >/dev/null 2>&1 || : + +%files server-minimal +%defattr(-, root, root, -) +%doc %{?license_files_server} +%doc %{src_dir}/Docs/INFO_SRC* +%doc release/Docs/INFO_BIN* +%config(noreplace) %{_sysconfdir}/my.cnf +%dir %{_sysconfdir}/my.cnf.d +%attr(755, root, root) %{_sbindir}/mysqld +%attr(755, root, root) %{_bindir}/mysql +%attr(755, root, root) %{_bindir}/mysqldump +%attr(755, root, root) %{_bindir}/mysql_config +%attr(755, root, root) %{_bindir}/mysql_install_db +%attr(755, root, root) %{_bindir}/mysql_tzinfo_to_sql +%attr(755, root, root) %{_bindir}/mysql_upgrade +%attr(755, root, root) %{_bindir}/my_print_defaults +%dir %{_libdir}/mysql/plugin +%attr(755, root, root) %{_libdir}/mysql/plugin/adt_null.so +%attr(755, root, root) %{_libdir}/mysql/plugin/auth_socket.so +%attr(755, root, root) %{_libdir}/mysql/plugin/mypluglib.so +%attr(755, root, root) %{_libdir}/mysql/plugin/semisync_master.so +%attr(755, root, root) %{_libdir}/mysql/plugin/semisync_slave.so +%dir %{_datadir}/mysql/ +%{_datadir}/mysql/charsets/ +%{_datadir}/mysql/czech/ +%{_datadir}/mysql/danish/ +%{_datadir}/mysql/dutch/ +%{_datadir}/mysql/english/ +%{_datadir}/mysql/estonian/ +%{_datadir}/mysql/french/ +%{_datadir}/mysql/german/ +%{_datadir}/mysql/greek/ +%{_datadir}/mysql/hungarian/ +%{_datadir}/mysql/italian/ +%{_datadir}/mysql/japanese/ +%{_datadir}/mysql/korean/ +%{_datadir}/mysql/norwegian-ny/ +%{_datadir}/mysql/norwegian/ +%{_datadir}/mysql/polish/ +%{_datadir}/mysql/portuguese/ +%{_datadir}/mysql/romanian/ +%{_datadir}/mysql/russian/ +%{_datadir}/mysql/serbian/ +%{_datadir}/mysql/slovak/ +%{_datadir}/mysql/spanish/ +%{_datadir}/mysql/swedish/ +%{_datadir}/mysql/ukrainian/ +%attr(644, root, root) %{_datadir}/mysql/errmsg-utf8.txt +%attr(644, root, root) %{_datadir}/mysql/fill_help_tables.sql +%attr(644, root, root) %{_datadir}/mysql/mysql_system_tables.sql +%attr(644, root, root) %{_datadir}/mysql/mysql_system_tables_data.sql +%attr(644, root, root) %{_datadir}/mysql/mysql_test_data_timezone.sql +%attr(644, root, root) %{_datadir}/mysql/magic +%dir %attr(750, mysql, mysql) /var/lib/mysql +%dir %attr(755, mysql, mysql) /var/run/mysqld +%dir %attr(750, mysql, mysql) /var/lib/mysql-files + +%changelog +* Mon Feb 16 2015 Terje Rosten - 5.5.42-1 +- Port to 5.5. + +* Mon Feb 16 2015 Terje Rosten - 5.7.6-0.3.m16 +- Introduce minimal server for docker + +* Tue Feb 3 2015 Balasubramanian Kandasamy - 5.7.6-0.2.m16 +- Include boost sources +- Fix cmake buildrequires +- Fix build on el5 with gcc44 +- Add license info in each subpackage +- Soname bump, more compat packages +- Updated default shell for mysql user +- Added mysql_ssl_rsa_setup +- Include mysql-files directory + +* Thu Sep 18 2014 Balasubramanian Kandasamy - 5.7.6-0.2.m16 +- Provide replication_observers_example_plugin.so plugin + +* Tue Sep 2 2014 Bjorn Munch - 5.7.6-0.1.m16 +- Updated for 5.7.6 + +* Fri Aug 08 2014 Erlend Dahl - 5.7.5-0.6.m15 +- Provide mysql_no_login.so plugin + +* Wed Aug 06 2014 Balasubramanian Kandasamy - 5.7.5-0.5.m15 +- Provide mysql-compat-server dependencies + +* Wed Jul 09 2014 Balasubramanian Kandasamy - 5.7.5-0.4.m15 +- Remove perl(GD) and dtrace dependencies + +* Thu Jun 26 2014 Balasubramanian Kandasamy - 5.7.5-0.3.m15 +- Resolve embedded-devel conflict issue + +* Wed Jun 25 2014 Balasubramanian Kandasamy - 5.7.5-0.2.m15 +- Add bench package +- Enable dtrace + +* Thu Apr 24 2014 Balasubramanian Kandasamy - 5.7.5-0.1.m15 +- Updated for 5.7.5 + +* Mon Apr 07 2014 Balasubramanian Kandasamy - 5.7.4-0.5.m14 +- Fix Cflags for el7 + +* Mon Mar 31 2014 Balasubramanian Kandasamy - 5.7.4-0.4.m14 +- Support for enterprise packages +- Upgrade from MySQL-* packages + +* Wed Mar 12 2014 Balasubramanian Kandasamy - 5.7.4-0.3.m14 +- Resolve conflict with mysql-libs-compat + +* Thu Mar 06 2014 Balasubramanian Kandasamy - 5.7.4-0.2.m14 +- Resolve conflict issues during upgrade +- Add ha_example.so plugin which is now included + +* Fri Feb 07 2014 Balasubramanian Kandasamy - 5.7.4-0.1.m14 +- 5.7.4 +- Enable shared libmysqld by cmake option +- Move mysqltest and test plugins to test subpackage + +* Mon Nov 18 2013 Balasubramanian Kandasamy - 5.7.3-0.3.m13 +- Fixed isa_bits error + +* Fri Oct 25 2013 Balasubramanian Kandasamy - 5.7.3-0.1.m13 +- Initial 5.7 port + +* Fri Oct 25 2013 Balasubramanian Kandasamy - 5.6.15-1 +- Fixed uln advanced rpm libyassl.a error +- Updated to 5.6.15 + +* Wed Oct 16 2013 Balasubramanian Kandasamy - 5.6.14-3 +- Fixed mysql_install_db usage +- Improved handling of plugin directory + +* Fri Sep 27 2013 Balasubramanian Kandasamy - 5.6.14-2 +- Refresh mysql-install patch and service renaming + +* Mon Sep 16 2013 Balasubramanian Kandasamy - 5.6.14-1 +- Updated to 5.6.14 + +* Wed Sep 04 2013 Balasubramanian Kandasamy - 5.6.13-5 +- Support upgrade from 5.5 ULN packages to 5.6 + +* Tue Aug 27 2013 Balasubramanian Kandasamy - 5.6.13-4 +- Enhanced perl filtering +- Added openssl-devel to buildreq + +* Wed Aug 21 2013 Balasubramanian Kandasamy - 5.6.13-3 +- Removed mysql_embedded binary to resolve multilib conflict issue + +* Fri Aug 16 2013 Balasubramanian Kandasamy - 5.6.13-2 +- Fixed Provides and Obsoletes issues in server, test packages + +* Wed Aug 14 2013 Balasubramanian Kandasamy - 5.6.13-1 +- Updated to 5.6.13 + +* Mon Aug 05 2013 Balasubramanian Kandasamy - 5.6.12-9 +- Added files list to embedded packages + +* Thu Aug 01 2013 Balasubramanian Kandasamy - 5.6.12-8 +- Updated libmysqld.a with libmysqld.so in embedded package + +* Mon Jul 29 2013 Balasubramanian Kandasamy - 5.6.12-7 +- Updated test package dependency from client to server + +* Wed Jul 24 2013 Balasubramanian Kandasamy - 5.6.12-6 +- Added libs-compat dependency under libs package to resolve server + installation conflicts issue. + +* Wed Jul 17 2013 Balasubramanian Kandasamy - 5.6.12-5 +- Removed libmysqlclient.so.16 from libs package + +* Fri Jul 05 2013 Balasubramanian Kandasamy - 5.6.12-4 +- Adjusted to work on OEL6 + +* Wed Jun 26 2013 Balasubramanian Kandasamy - 5.6.12-3 +- Move libs to mysql/ +- Basic multi arch support +- Fix changelog dates + +* Thu Jun 20 2013 Balasubramanian Kandasamy - 5.6.12-2 +- Major cleanup + +* Tue Jun 04 2013 Balasubramanian Kandasamy - 5.6.12-1 +- Updated to 5.6.12 + +* Mon Nov 05 2012 Joerg Bruehe + +- Allow to override the default to use the bundled yaSSL by an option like + --define="with_ssl /path/to/ssl" + +* Wed Oct 10 2012 Bjorn Munch + +- Replace old my-*.cnf config file examples with template my-default.cnf + +* Fri Oct 05 2012 Joerg Bruehe + +- Let the installation use the new option "--random-passwords" of "mysql_install_db". + (Bug# 12794345 Ensure root password) +- Fix an inconsistency: "new install" vs "upgrade" are told from the (non)existence + of "$mysql_datadir/mysql" (holding table "mysql.user" and other system stuff). + +* Tue Jul 24 2012 Joerg Bruehe + +- Add a macro "runselftest": + if set to 1 (default), the test suite will be run during the RPM build; + this can be oveeridden via the command line by adding + --define "runselftest 0" + Failures of the test suite will NOT make the RPM build fail! + +* Mon Jul 16 2012 Joerg Bruehe + +- Add the man page for the "mysql_config_editor". + +* Mon Jun 11 2012 Joerg Bruehe + +- Make sure newly added "SPECIFIC-ULN/" directory does not disturb packaging. + +* Wed Feb 29 2012 Brajmohan Saxena + +- Removal all traces of the readline library from mysql (BUG 13738013) + +* Wed Sep 28 2011 Joerg Bruehe + +- Fix duplicate mentioning of "mysql_plugin" and its manual page, + it is better to keep alphabetic order in the files list (merging!). + +* Wed Sep 14 2011 Joerg Bruehe + +- Let the RPM capabilities ("obsoletes" etc) ensure that an upgrade may replace + the RPMs of any configuration (of the current or the preceding release series) + by the new ones. This is done by not using the implicitly generated capabilities + (which include the configuration name) and relying on more generic ones which + just list the function ("server", "client", ...). + The implicit generation cannot be prevented, so all these capabilities must be + explicitly listed in "Obsoletes:" + +* Tue Sep 13 2011 Jonathan Perkin + +- Add support for Oracle Linux 6 and Red Hat Enterprise Linux 6. Due to + changes in RPM behaviour ($RPM_BUILD_ROOT is removed prior to install) + this necessitated a move of the libmygcc.a installation to the install + phase, which is probably where it belonged in the first place. + +* Tue Sep 13 2011 Joerg Bruehe + +- "make_win_bin_dist" and its manual are dropped, cmake does it different. + +* Thu Sep 08 2011 Daniel Fischer + +- Add mysql_plugin man page. + +* Tue Aug 30 2011 Tor Didriksen + +- Set CXX=g++ by default to add a dependency on libgcc/libstdc++. + Also, remove the use of the -fno-exceptions and -fno-rtti flags. + TODO: update distro_buildreq/distro_requires + +* Tue Aug 30 2011 Joerg Bruehe + +- Add the manual page for "mysql_plugin" to the server package. + +* Fri Aug 19 2011 Joerg Bruehe + +- Null-upmerge the fix of bug#37165: This spec file is not affected. +- Replace "/var/lib/mysql" by the spec file variable "%%{mysqldatadir}". + +* Fri Aug 12 2011 Daniel Fischer + +- Source plugin library files list from cmake-generated file. + +* Mon Jul 25 2011 Chuck Bell + +- Added the mysql_plugin client - enables or disables plugins. + +* Thu Jul 21 2011 Sunanda Menon + +- Fix bug#12561297: Added the MySQL embedded binary + +* Thu Jul 07 2011 Joerg Bruehe + +- Fix bug#45415: "rpm upgrade recreates test database" + Let the creation of the "test" database happen only during a new installation, + not in an RPM upgrade. + This affects both the "mkdir" and the call of "mysql_install_db". + +* Wed Feb 09 2011 Joerg Bruehe + +- Fix bug#56581: If an installation deviates from the default file locations + ("datadir" and "pid-file"), the mechanism to detect a running server (on upgrade) + should still work, and use these locations. + The problem was that the fix for bug#27072 did not check for local settings. + +* Mon Jan 31 2011 Joerg Bruehe + +- Install the new "manifest" files: "INFO_SRC" and "INFO_BIN". + +* Tue Nov 23 2010 Jonathan Perkin + +- EXCEPTIONS-CLIENT has been deleted, remove it from here too +- Support MYSQL_BUILD_MAKE_JFLAG environment variable for passing + a '-j' argument to make. + +* Mon Nov 1 2010 Georgi Kodinov + +- Added test authentication (WL#1054) plugin binaries + +* Wed Oct 6 2010 Georgi Kodinov + +- Added example external authentication (WL#1054) plugin binaries + +* Wed Aug 11 2010 Joerg Bruehe + +- With a recent spec file cleanup, names have changed: A "-community" part was dropped. + Reflect that in the "Obsoletes" specifications. +- Add a "triggerpostun" to handle the uninstall of the "-community" server RPM. +- This fixes bug#55015 "MySQL server is not restarted properly after RPM upgrade". + +* Tue Jun 15 2010 Joerg Bruehe + +- Change the behaviour on installation and upgrade: + On installation, do not autostart the server. + *Iff* the server was stopped before the upgrade is started, this is taken as a + sign the administrator is handling that manually, and so the new server will + not be started automatically at the end of the upgrade. + The start/stop scripts will still be installed, so the server will be started + on the next machine boot. + This is the 5.5 version of fixing bug#27072 (RPM autostarting the server). + +* Tue Jun 1 2010 Jonathan Perkin + +- Implement SELinux checks from distribution-specific spec file. + +* Wed May 12 2010 Jonathan Perkin + +- Large number of changes to build using CMake +- Introduce distribution-specific RPMs +- Drop debuginfo, build all binaries with debug/symbols +- Remove __os_install_post, use native macro +- Remove _unpackaged_files_terminate_build, make it an error to have + unpackaged files +- Remove cluster RPMs + +* Wed Mar 24 2010 Joerg Bruehe + +- Add "--with-perfschema" to the configure options. + +* Mon Mar 22 2010 Joerg Bruehe + +- User "usr/lib*" to allow for both "usr/lib" and "usr/lib64", + mask "rmdir" return code 1. +- Remove "ha_example.*" files from the list, they aren't built. + +* Wed Mar 17 2010 Joerg Bruehe + +- Fix a wrong path name in handling the debug plugins. + +* Wed Mar 10 2010 Joerg Bruehe + +- Take the result of the debug plugin build and put it into the optimized tree, + so that it becomes part of the final installation; + include the files in the packlist. Part of the fixes for bug#49022. + +* Mon Mar 01 2010 Joerg Bruehe + +- Set "Oracle and/or its affiliates" as the vendor and copyright owner, + accept upgrading from packages showing MySQL or Sun as vendor. + +* Fri Feb 12 2010 Joerg Bruehe + +- Formatting changes: + Have a consistent structure of separator lines and of indentation + (8 leading blanks => tab). +- Introduce the variable "src_dir". +- Give the environment variables "MYSQL_BUILD_CC(CXX)" precedence + over "CC" ("CXX"). +- Drop the old "with_static" argument analysis, this is not supported + in 5.1 since ages. +- Introduce variables to control the handlers individually, as well + as other options. +- Use the new "--with-plugin" notation for the table handlers. +- Drop handling "/etc/rc.d/init.d/mysql", the switch to "/etc/init.d/mysql" + was done back in 2002 already. +- Make "--with-zlib-dir=bundled" the default, add an option to disable it. +- Add missing manual pages to the file list. +- Improve the runtime check for "libgcc.a", protect it against being tried + with the Intel compiler "icc". + +* Mon Jan 11 2010 Joerg Bruehe + +- Change RPM file naming: + - Suffix like "-m2", "-rc" becomes part of version as "_m2", "_rc". + - Release counts from 1, not 0. + +* Wed Dec 23 2009 Joerg Bruehe + +- The "semisync" plugin file name has lost its introductory "lib", + adapt the file lists for the subpackages. + This is a part missing from the fix for bug#48351. +- Remove the "fix_privilege_tables" manual, it does not exist in 5.5 + (and likely, the whole script will go, too). + +* Mon Nov 16 2009 Joerg Bruehe + +- Fix some problems with the directives around "tcmalloc" (experimental), + remove erroneous traces of the InnoDB plugin (that is 5.1 only). + +* Tue Oct 06 2009 Magnus Blaudd + +- Removed mysql_fix_privilege_tables + +* Fri Oct 02 2009 Alexander Nozdrin + +- "mysqlmanager" got removed from version 5.4, all references deleted. + +* Fri Aug 28 2009 Joerg Bruehe + +- Merge up from 5.1 to 5.4: Remove handling for the InnoDB plugin. + +* Thu Aug 27 2009 Joerg Bruehe + +- This version does not contain the "Instance manager", "mysqlmanager": + Remove it from the spec file so that packaging succeeds. + +* Mon Aug 24 2009 Jonathan Perkin + +- Add conditionals for bundled zlib and innodb plugin + +* Fri Aug 21 2009 Jonathan Perkin + +- Install plugin libraries in appropriate packages. +- Disable libdaemon_example and ftexample plugins. + +* Thu Aug 20 2009 Jonathan Perkin + +- Update variable used for mysql-test suite location to match source. + +* Fri Nov 07 2008 Joerg Bruehe + +- Correct yesterday's fix, so that it also works for the last flag, + and fix a wrong quoting: un-quoted quote marks must not be escaped. + +* Thu Nov 06 2008 Kent Boortz + +- Removed "mysql_upgrade_shell" +- Removed some copy/paste between debug and normal build + +* Thu Nov 06 2008 Joerg Bruehe + +- Modify CFLAGS and CXXFLAGS such that a debug build is not optimized. + This should cover both gcc and icc flags. Fixes bug#40546. + +* Fri Aug 29 2008 Kent Boortz + +- Removed the "Federated" storage engine option, and enabled in all + +* Tue Aug 26 2008 Joerg Bruehe + +- Get rid of the "warning: Installed (but unpackaged) file(s) found:" + Some generated files aren't needed in RPMs: + - the "sql-bench/" subdirectory + Some files were missing: + - /usr/share/aclocal/mysql.m4 ("devel" subpackage) + - Manual "mysqlbug" ("server" subpackage) + - Program "innochecksum" and its manual ("server" subpackage) + - Manual "mysql_find_rows" ("client" subpackage) + - Script "mysql_upgrade_shell" ("client" subpackage) + - Program "ndb_cpcd" and its manual ("ndb-extra" subpackage) + - Manuals "ndb_mgm" + "ndb_restore" ("ndb-tools" subpackage) + +* Mon Mar 31 2008 Kent Boortz + +- Made the "Federated" storage engine an option +- Made the "Cluster" storage engine and sub packages an option + +* Wed Mar 19 2008 Joerg Bruehe + +- Add the man pages for "ndbd" and "ndb_mgmd". + +* Mon Feb 18 2008 Timothy Smith + +- Require a manual upgrade if the alread-installed mysql-server is + from another vendor, or is of a different major version. + +* Wed May 02 2007 Joerg Bruehe + +- "ndb_size.tmpl" is not needed any more, + "man1/mysql_install_db.1" lacked the trailing '*'. + +* Sat Apr 07 2007 Kent Boortz + +- Removed man page for "mysql_create_system_tables" + +* Wed Mar 21 2007 Daniel Fischer + +- Add debug server. + +* Mon Mar 19 2007 Daniel Fischer + +- Remove Max RPMs; the server RPMs contain a mysqld compiled with all + features that previously only were built into Max. + +* Fri Mar 02 2007 Joerg Bruehe + +- Add several man pages for NDB which are now created. + +* Fri Jan 05 2007 Kent Boortz + +- Put back "libmygcc.a", found no real reason it was removed. + +- Add CFLAGS to gcc call with --print-libgcc-file, to make sure the + correct "libgcc.a" path is returned for the 32/64 bit architecture. + +* Mon Dec 18 2006 Joerg Bruehe + +- Fix the move of "mysqlmanager" to section 8: Directory name was wrong. + +* Thu Dec 14 2006 Joerg Bruehe + +- Include the new man pages for "my_print_defaults" and "mysql_tzinfo_to_sql" + in the server RPM. +- The "mysqlmanager" man page got moved from section 1 to 8. + +* Thu Nov 30 2006 Joerg Bruehe + +- Call "make install" using "benchdir_root=%%{_datadir}", + because that is affecting the regression test suite as well. + +* Thu Nov 16 2006 Joerg Bruehe + +- Explicitly note that the "MySQL-shared" RPMs (as built by MySQL AB) + replace "mysql-shared" (as distributed by SuSE) to allow easy upgrading + (bug#22081). + +* Mon Nov 13 2006 Joerg Bruehe + +- Add "--with-partition" t 2006 Joerg Bruehe + +- Use the Perl script to run the tests, because it will automatically check + whether the server is configured with SSL. + +* Tue Jun 27 2006 Joerg Bruehe + +- move "mysqldumpslow" from the client RPM to the server RPM (bug#20216) + +- Revert all previous attempts to call "mysql_upgrade" during RPM upgrade, + there are some more aspects which need to be solved before this is possible. + For now, just ensure the binary "mysql_upgrade" is delivered and installysql.com> + +- To run "mysql_upgrade", we need a running server; + start it in isolation and skip password checks. + +* Sat May 20 2006 Kent Boortz + +- Always compile for PIC, position independent code. + +* Wed May 10 2006 Kent Boortz + +- Use character set "all" when compiling with Cluster, to make Cluster + nodes independent on the character set directory, and the problem + that two RPM sub packages both wants to install this directory. + +* Mon May 01 2006 Kent Boortz + +- Use "./libtool --mode=execute" instead of searching for the + executable in current directory and ".libs". + +* Fri Apr 28 2006 Kent Boortz + +- Install and run "mysql_upgrade" + +* Wed Apr 12 2006 Jim Winstead + +- Remove sql-bench, and MySQL-bench RPM (will be built as an independent + project from the mysql-bench repository) + +* Tue Apr 11 2006 Jim Winstead + +- Remove old mysqltestmanager and related programs +* Sat Apr 01 2006 Kent Boortz + +- Set $LDFLAGS from $MYSQL_BUILD_LDFLAGS + +* Tue Mar 07 2006 Kent Boortz + +- Changed product name from "Community Edition" to "Community Server" + +* Mon Mar 06 2006 Kent Boortz + +- Fast mutexes is now disabled by default, but should be + used in Linux builds. + +* Mon Feb 20 2006 Kent Boortz + +- Reintroduced a max build +- Limited testing of 'debug' and 'max' servers +- Berkeley DB only in 'max' + +* Mon Feb 13 2006 Joerg Bruehe + +- Use "-i" on "make test-force"; + this is essential for later evaluation of this log file. + +* Thu Feb 09 2006 Kent Boortz + +- Pass '-static' to libtool, link static with our own libraries, dynamic + with system libraries. Link with the bundled zlib. + +* Wed Feb 08 2006 Kristian Nielsen + +- Modified RPM spec to match new 5.1 debug+max combined community packaging. + +* Sun Dec 18 2005 Kent Boortz + +- Added "client/mysqlslap" + +* Mon Dec 12 2005 Rodrigo Novo + +- Added zlib to the list of (static) libraries installed +- Added check against libtool wierdness (WRT: sql/mysqld || sql/.libs/mysqld) +- Compile MySQL with bundled zlib +- Fixed %%packager name to "MySQL Production Engineering Team" + +* Mon Dec 05 2005 Joerg Bruehe + +- Avoid using the "bundled" zlib on "shared" builds: + As it is not installed (on the build system), this gives dependency + problems with "libtool" causing the build to fail. + (Change was done on Nov 11, but left uncommented.) + +* Tue Nov 22 2005 Joerg Bruehe + +- Extend the file existence check for "init.d/mysql" on un-install + to also guard the call to "insserv"/"chkconfig". + +* Thu Oct 27 2005 Lenz Grimmer + +- added more man pages + +* Wed Oct 19 2005 Kent Boortz + +- Made yaSSL support an option (off by default) + +* Wed Oct 19 2005 Kent Boortz + +- Enabled yaSSL support + +* Sat Oct 15 2005 Kent Boortz + +- Give mode arguments the same way in all places +lenz@mysql.com> + +- fixed the removing of the RPM_BUILD_ROOT in the %%clean section (the + $RBR variable did not get expanded, thus leaving old build roots behind) + +* Thu Aug 04 2005 Lenz Grimmer + +- Fixed the creation of the mysql user group account in the postinstall + section (BUG 12348) +- Fixed enabling the Archive storage engine in the Max binary + +* Tue Aug 02 2005 Lenz Grimmer + +- Fixed the Requires: tag for the server RPM (BUG 12233) + +* Fri Jul 15 2005 Lenz Grimmer + +- create a "mysql" user group and assign the mysql user account to that group + in the server postinstall section. (BUG 10984) + +* Tue Jun 14 2005 Lenz Grimmer + +- Do not build statically on i386 by default, only when adding either "--with + static" or "--define '_with_static 1'" to the RPM build options. Static + linking really only makes sense when linking against the specially patched + glibc 2.2.5. + +* Mon Jun 06 2005 Lenz Grimmer + +- added mysql_client_test to the "bench" subpackage (BUG 10676) +- added the libndbclient static and shared libraries (BUG 10676) + +* Wed Jun 01 2005 Lenz Grimmer + +- use "mysqldatadir" variable instead of hard-coding the path multiple times +- use the "mysqld_user" variable on all occasions a user name is referenced +- removed (incomplete) Brazilian translations +- removed redundant release tags from the subpackage descriptions + +* Wed May 25 2005 Joerg Bruehe + +- Added a "make clean" between separate calls to "BuildMySQL". + +* Thu May 12 2005 Guilhem Bichot + +- Removed the mysql_tableinfo script made obsolete by the information schema + +* Wed Apr 20 2005 Lenz Grimmer + +- Enabled the "blackhole" storage engine for the Max RPM + +* Wed Apr 13 2005 Lenz Grimmer + +- removed the MySQL manual files (html/ps/texi) - they have been removed + from the MySQL sources and are now available seperately. + +* Mon Apr 4 2005 Petr Chardin + +- old mysqlmanager, mysq* Mon Feb 7 2005 Tomas Ulin + +- enabled the "Ndbcluster" storage engine for the max binary +- added extra make install in ndb subdir after Max build to get ndb binaries +- added packages for ndbcluster storage engine + +* Fri Jan 14 2005 Lenz Grimmer + +- replaced obsoleted "BuildPrereq" with "BuildRequires" instead + +* Thu Jan 13 2005 Lenz Grimmer + +- enabled the "Federated" storage engine for the max binary + +* Tue Jan 04 2005 Petr Chardin + +- ISAM and merge storage engines were purged. As well as appropriate + tools and manpages (isamchk and isamlog) + +* Fri Dec 31 2004 Lenz Grimmer + +- enabled the "Archive" storage engine for the max binary +- enabled the "CSV" storage engine for the max binary +- enabled the "Example" storage engine for the max binary + +* Thu Aug 26 2004 Lenz Grimmer + +- MySQL-Max now requires MySQL-server instead of MySQL (BUG 3860) + +* Fri Aug 20 2004 Lenz Grimmer + +- do not link statically on IA64/AMD64 as these systems do not have + a patched glibc installed + +* Tue Aug 10 2004 Lenz Grimmer + +- Added libmygcc.a to the devel subpackage (required to link applications + against the the embedded server libmysqld.a) (BUG 4921) + +* Mon Aug 09 2004 Lenz Grimmer + +- Added EXCEPTIONS-CLIENT to the "devel" package + +* Thu Jul 29 2004 Lenz Grimmer + +- disabled OpenSSL in the Max binaries again (the RPM packages were the + only exception to this anyway) (BUG 1043) + +* Wed Jun 30 2004 Lenz Grimmer + +- fixed server postinstall (mysql_install_db was called with the wrong + parameter) + +* Thu Jun 24 2004 Lenz Grimmer + +- added mysql_tzinfo_to_sql to the server subpackage +- run "make clean" instead of "make distclean" + +* Mon Apr 05 2004 Lenz Grimmer + +- added ncurses-devel to the build prerequisites (BUG 3377) + +* Thu Feb 12 2004 Lenz Grimmer + +- when using gcc, _always_ use CXX=gcc +- replaced Copyright with License field (Copyright is obsolete) + +* Tue Feb 03 2004 Lenz Grimmer + +- added myisam_ftdump to the Server package + +* Tue Jan 13 2004 Lenz Grimmer + +- link the mysql client against libreadline instead of libedit (BUG 2289) + +* Mon Dec 22 2003 Lenz Grimmer + +- marked /etc/logrotate.d/mysql as a config file (BUG 2156) + +* Sat Dec 13 2003 Lenz Grimmer + +- fixed file permissions (BUG 1672) + +* Thu Dec 11 2003 Lenz Grimmer + +- made testing for gcc3 a bit more robust + +* Fri Dec 05 2003 Lenz Grimmer + +- added missing file mysql_create_system_tables to the server subpackage + +* Fri Nov 21 2003 Lenz Grimmer + +- removed dependency on MySQL-client from the MySQL-devel subpackage + as it is not really required. (BUG 1610) + +* Fri Aug 29 2003 Lenz Grimmer + +- Fixed BUG 1162 (removed macro names from the changelog) +- Really fixed BUG 998 (disable the checking for installed but + unpackaged files) + +* Tue Aug 05 2003 Lenz Grimmer + +- Fixed BUG 959 (libmysqld not being compiled properly) +- Fixed BUG 998 (RPM build errors): added missing files to the + distribution (mysql_fix_extensions, mysql_tableinfo, mysqldumpslow, + mysql_fix_privilege_tables.1), removed "-n" from install section. + +* Wed Jul 09 2003 Lenz Grimmer + +- removed the GIF Icon (file was not included in the sources anyway) +- removed unused variable shared_lib_version +- do not run automake before building the standard binary + (should not be necessary) +- add server suffix '-standard' to standard binary (to be in line + with the binary tarball distributions) +- Use more RPM macros (_exec_prefix, _sbindir, _libdir, _sysconfdir, + _datadir, _includedir) throughout the spec file. +- allow overriding CC and CXX (required when building with other compilers) + +* Fri May 16 2003 Lenz Grimmer + +- re-enabled RAID again + +* Wed Apr 30 2003 Lenz Grimmer + +- disabled MyISAM RAID (--with-raid)- it throws an assertion which + needs to be investigated first. + +* Mon Mar 10 2003 Lenz Grimmer + +- added missing file mysql_secure_installation to server subpackage + (BUG 141) + +* Tue Feb 11 2003 Lenz Grimmer + +- re-added missing pre- and post(un)install scripts to server subpackage +- added config file /etc/my.cnf to the file list (just for completeness) +- make sure to create the datadir with 755 permissions + +* Mon Jan 27 2003 Lenz Grimmer + +- removed unusedql.com> + +- Reworked the build steps a little bit: the Max binary is supposed + to include OpenSSL, which cannot be linked statically, thus trying + to statically link against a special glibc is futile anyway +- because of this, it is not required to make yet another build run + just to compile the shared libs (saves a lot of time) +- updated package description of the Max subpackage +- clean up the BuildRoot directory afterwards + +* Mon Jul 15 2002 Lenz Grimmer + +- Updated Packager information +- Fixed the build options: the regular package is supposed to + include InnoDB and linked statically, while the Max package + should include BDB and SSL support + +* Fri May 03 2002 Lenz Grimmer + +- Use more RPM macros (e.g. infodir, mandir) to make the spec + file more portable +- reorganized the installation of documentation files: let RPM + take care of this +- reorganized the file list: actually install man pages along + with the binaries of the respective subpackage +- do not include libmysqld.a in the devel subpackage as well, if we + have a special "embedded" subpackage +- reworked the package descriptions + +* Mon Oct 8 2001 Monty + +- Added embedded server as a separate RPM + +* Fri Apr 13 2001 Monty + +- Added mysqld-max to the distribution + +* Tue Jan 2 2001 Monty + +- Added mysql-test to the bench package + +* Fri Aug 18 2000 Tim Smith + +- Added separate libmysql_r directory; now both a threaded + and non-threaded library is shipped. + +* Tue Sep 28 1999 David Axmark + +- Added the support-files/my-example.cnf to the docs directory. + +- Removed devel dependency on base since it is about client + development. + +* Wed Sep 8 1999 David Axmark + +- Cleaned up some for 3.23. + +* Thu Jul 1 1999 David Axmark + +- Added support for shared libraries in a separate sub + package. Original fix by David Fox (dsfox@cogsci.ucsd.edu) + +- The --enable-assembler switch is now automatically disables on + platforms there assembler code is unavailable. This should allow + building this RPM on non i386 systems. + +* Mon Feb 22 1999 David Axmark + +- Removed unportable cc switches from the spec file. The defaults can + now be overridden with environment variables. This feature is used + to compile the official RPM with optimal (but compiler version + specific) switches. + +- Removed the repetitive description parts for the sub rpms. Maybe add + again if RPM gets a multiline macro capability. + +- Added support for a pt_BR translation. Translation contributed by + Jorge Godoy . + +* Wed Nov 4 1998 David Axmark + +- A lot of changes in all the rpm and install scripts. This may even + be a working RPM :-) + +* Sun Aug 16 1998 David Axmark + +- A developers changelog for MySQL is available in the source RPM. And + there is a history of major user visible changed in the Reference + Manual. Only RPM specific changes will be documented here. From 5768c0adf5f4cbc7036bfc14c81b9732f1c416b1 Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Tue, 16 Jun 2015 13:56:28 +0200 Subject: [PATCH 17/47] Updated CMakeLists.txt to include rpm-docker directory --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f18a388825a75..586119b2ffba8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -415,6 +415,7 @@ IF(NOT WITHOUT_SERVER) ENDIF() ADD_SUBDIRECTORY(packaging/rpm-oel) ADD_SUBDIRECTORY(packaging/rpm-sles) + ADD_SUBDIRECTORY(packaging/rpm-docker) ENDIF() INCLUDE(cmake/abi_check.cmake) From bb7951ae9558d1af6ddbae443f215ba7b788414f Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Wed, 17 Jun 2015 11:04:13 +0200 Subject: [PATCH 18/47] Bug#21262883 - MYSQL-SYSTEMD-START SCRIPT ERROR WHEN USING OPTION DATADIR OR SIMILAR Fixed the syntax in mysql-systemd-start script --- packaging/rpm-oel/mysql-systemd-start | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpm-oel/mysql-systemd-start b/packaging/rpm-oel/mysql-systemd-start index 8670f889574ef..12a1b16db806d 100644 --- a/packaging/rpm-oel/mysql-systemd-start +++ b/packaging/rpm-oel/mysql-systemd-start @@ -13,7 +13,7 @@ get_option () { local option=$2 local default=$3 ret=$(/usr/bin/my_print_defaults $section | grep '^--'${option}'=' | cut -d= -f2-) - [ -z $ret ] && ret=$default + [ -z "$ret" ] && ret=$default echo $ret } From 0dedf55d5d12d70f8c81f61ca562b312ae66a9f1 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 17 Jun 2015 13:44:32 +0200 Subject: [PATCH 19/47] Bug#19660891 HANDLE_FATAL_SIGNAL (SIG=11) IN QUEUE_INSERT Backport from 5.6 to 5.5 This makes filesort robust to misc variants of order by / group by on columns/expressions with zero length. --- mysys/ptr_cmp.c | 15 ++++++++++++++- sql/filesort.cc | 3 --- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c index 6f9ab13c82b30..cbd8ef49ef58d 100644 --- a/mysys/ptr_cmp.c +++ b/mysys/ptr_cmp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,6 +41,16 @@ static int native_compare(size_t *length, unsigned char **a, unsigned char **b) #else /* __sun */ +/** + Special case for ORDER BY / GROUP BY CHAR(0) NOT NULL + */ +static +int ptr_compare_zero_length(size_t *compare_length __attribute__((unused)), + uchar **a __attribute__((unused)), + uchar **b __attribute__((unused))) +{ + return 0; +} static int ptr_compare(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_0(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_1(size_t *compare_length, uchar **a, uchar **b); @@ -58,6 +68,8 @@ qsort2_cmp get_ptr_compare (size_t size __attribute__((unused))) #else qsort2_cmp get_ptr_compare (size_t size) { + if (size == 0) + return (qsort2_cmp) ptr_compare_zero_length; if (size < 4) return (qsort2_cmp) ptr_compare; switch (size & 3) { @@ -85,6 +97,7 @@ static int ptr_compare(size_t *compare_length, uchar **a, uchar **b) reg3 int length= *compare_length; reg1 uchar *first,*last; + DBUG_ASSERT(length > 0); first= *a; last= *b; while (--length) { diff --git a/sql/filesort.cc b/sql/filesort.cc index 98900efb0d509..df48cdb273d84 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -265,9 +265,6 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, } else { - /* filesort cannot handle zero-length records during merge. */ - DBUG_ASSERT(param.sort_length != 0); - if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer) { my_free(table_sort.buffpek); From dbbe747e54a320d810fff1896ed9e553d43a0bae Mon Sep 17 00:00:00 2001 From: V S Murthy Sidagam Date: Fri, 19 Jun 2015 08:26:33 +0530 Subject: [PATCH 20/47] Bug #21221862 NEWEST RHEL/CENTOS OPENSSL UPDATE BREAKS MYSQL DHE CIPHERS Description: The newest RHEL/CentOS/SL 6.6 openssl package (1.0.1e-30.el6_6.9; published around 6/4/2015) contains a fix for LogJam. RedHat's fix for this was to limit the use of any SSL DH key sizes to a minimum of 768 bits. This breaks any DHE SSL ciphers for MySQL clients as soon as you install the openssl update, since in vio/viosslfactories.c, the default DHPARAM is a 512 bit one. This cannot be changed in configuration/runtime; and needs a recompile. Because of this the client connection with --ssl-cipher=DHE-RSA-AES256-SHA is not able to connect the server. Analysis: Openssl has changed Diffie-Hellman key from the 512 to 1024 due to some reasons(please see the details at http://openssl.org/news/secadv_20150611.txt) Because of this the client with DHE cipher is failing to connect the server. This change took place from the openssl-1.0.1n onwards. Fix: Similar bug fix is already pushed to mysql-5.7 under bug#18367167. Hence we backported the same fix to mysql-5.5 and mysql-5.6. --- include/violite.h | 4 +-- vio/viosslfactories.c | 69 +++++++++++++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/include/violite.h b/include/violite.h index b35295caf5e01..817148ca3a105 100644 --- a/include/violite.h +++ b/include/violite.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -128,7 +128,7 @@ enum enum_ssl_init_error { SSL_INITERR_NOERROR= 0, SSL_INITERR_CERT, SSL_INITERR_KEY, SSL_INITERR_NOMATCH, SSL_INITERR_BAD_PATHS, SSL_INITERR_CIPHERS, - SSL_INITERR_MEMFAIL, SSL_INITERR_LASTERR + SSL_INITERR_MEMFAIL, SSL_INITERR_DHFAIL, SSL_INITERR_LASTERR }; const char* sslGetErrString(enum enum_ssl_init_error err); diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 7e475683f9a81..ea46d9c030285 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -20,27 +20,56 @@ static my_bool ssl_algorithms_added = FALSE; static my_bool ssl_error_strings_loaded= FALSE; -static unsigned char dh512_p[]= +/* + Diffie-Hellman key. + Generated using: >openssl dhparam -5 -C 2048 + + -----BEGIN DH PARAMETERS----- + MIIBCAKCAQEAil36wGZ2TmH6ysA3V1xtP4MKofXx5n88xq/aiybmGnReZMviCPEJ + 46+7VCktl/RZ5iaDH1XNG1dVQmznt9pu2G3usU+k1/VB4bQL4ZgW4u0Wzxh9PyXD + glm99I9Xyj4Z5PVE4MyAsxCRGA1kWQpD9/zKAegUBPLNqSo886Uqg9hmn8ksyU9E + BV5eAEciCuawh6V0O+Sj/C3cSfLhgA0GcXp3OqlmcDu6jS5gWjn3LdP1U0duVxMB + h/neTSCSvtce4CAMYMjKNVh9P1nu+2d9ZH2Od2xhRIqMTfAS1KTqF3VmSWzPFCjG + mjxx/bg6bOOjpgZapvB6ABWlWmRmAAWFtwIBBQ== + -----END DH PARAMETERS----- + */ +static unsigned char dh2048_p[]= { - 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75, - 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F, - 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3, - 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12, - 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C, - 0x47,0x74,0xE8,0x33, + 0x8A, 0x5D, 0xFA, 0xC0, 0x66, 0x76, 0x4E, 0x61, 0xFA, 0xCA, 0xC0, 0x37, + 0x57, 0x5C, 0x6D, 0x3F, 0x83, 0x0A, 0xA1, 0xF5, 0xF1, 0xE6, 0x7F, 0x3C, + 0xC6, 0xAF, 0xDA, 0x8B, 0x26, 0xE6, 0x1A, 0x74, 0x5E, 0x64, 0xCB, 0xE2, + 0x08, 0xF1, 0x09, 0xE3, 0xAF, 0xBB, 0x54, 0x29, 0x2D, 0x97, 0xF4, 0x59, + 0xE6, 0x26, 0x83, 0x1F, 0x55, 0xCD, 0x1B, 0x57, 0x55, 0x42, 0x6C, 0xE7, + 0xB7, 0xDA, 0x6E, 0xD8, 0x6D, 0xEE, 0xB1, 0x4F, 0xA4, 0xD7, 0xF5, 0x41, + 0xE1, 0xB4, 0x0B, 0xE1, 0x98, 0x16, 0xE2, 0xED, 0x16, 0xCF, 0x18, 0x7D, + 0x3F, 0x25, 0xC3, 0x82, 0x59, 0xBD, 0xF4, 0x8F, 0x57, 0xCA, 0x3E, 0x19, + 0xE4, 0xF5, 0x44, 0xE0, 0xCC, 0x80, 0xB3, 0x10, 0x91, 0x18, 0x0D, 0x64, + 0x59, 0x0A, 0x43, 0xF7, 0xFC, 0xCA, 0x01, 0xE8, 0x14, 0x04, 0xF2, 0xCD, + 0xA9, 0x2A, 0x3C, 0xF3, 0xA5, 0x2A, 0x83, 0xD8, 0x66, 0x9F, 0xC9, 0x2C, + 0xC9, 0x4F, 0x44, 0x05, 0x5E, 0x5E, 0x00, 0x47, 0x22, 0x0A, 0xE6, 0xB0, + 0x87, 0xA5, 0x74, 0x3B, 0xE4, 0xA3, 0xFC, 0x2D, 0xDC, 0x49, 0xF2, 0xE1, + 0x80, 0x0D, 0x06, 0x71, 0x7A, 0x77, 0x3A, 0xA9, 0x66, 0x70, 0x3B, 0xBA, + 0x8D, 0x2E, 0x60, 0x5A, 0x39, 0xF7, 0x2D, 0xD3, 0xF5, 0x53, 0x47, 0x6E, + 0x57, 0x13, 0x01, 0x87, 0xF9, 0xDE, 0x4D, 0x20, 0x92, 0xBE, 0xD7, 0x1E, + 0xE0, 0x20, 0x0C, 0x60, 0xC8, 0xCA, 0x35, 0x58, 0x7D, 0x3F, 0x59, 0xEE, + 0xFB, 0x67, 0x7D, 0x64, 0x7D, 0x8E, 0x77, 0x6C, 0x61, 0x44, 0x8A, 0x8C, + 0x4D, 0xF0, 0x12, 0xD4, 0xA4, 0xEA, 0x17, 0x75, 0x66, 0x49, 0x6C, 0xCF, + 0x14, 0x28, 0xC6, 0x9A, 0x3C, 0x71, 0xFD, 0xB8, 0x3A, 0x6C, 0xE3, 0xA3, + 0xA6, 0x06, 0x5A, 0xA6, 0xF0, 0x7A, 0x00, 0x15, 0xA5, 0x5A, 0x64, 0x66, + 0x00, 0x05, 0x85, 0xB7, }; -static unsigned char dh512_g[]={ - 0x02, +static unsigned char dh2048_g[]={ + 0x05, }; -static DH *get_dh512(void) +static DH *get_dh2048(void) { DH *dh; if ((dh=DH_new())) { - dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL); - dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL); + dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL); + dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL); if (! dh->p || ! dh->g) { DH_free(dh); @@ -81,7 +110,8 @@ ssl_error_string[] = "Private key does not match the certificate public key", "SSL_CTX_set_default_verify_paths failed", "Failed to set ciphers to use", - "SSL_CTX_new failed" + "SSL_CTX_new failed", + "SSL_CTX_set_tmp_dh failed" }; const char* @@ -258,8 +288,17 @@ new_VioSSLFd(const char *key_file, const char *cert_file, } /* DH stuff */ - dh=get_dh512(); - SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh); + dh= get_dh2048(); + if (SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh) == 0) + { + *error= SSL_INITERR_DHFAIL; + DBUG_PRINT("error", ("%s", sslGetErrString(*error))); + report_errors(); + DH_free(dh); + SSL_CTX_free(ssl_fd->ssl_context); + my_free(ssl_fd); + DBUG_RETURN(0); + } DH_free(dh); DBUG_PRINT("exit", ("OK 1")); From db2ed27e0ebe13fa70972b9993ff9bbd2f29499f Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Fri, 19 Jun 2015 10:17:36 +0530 Subject: [PATCH 21/47] Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE Problem: If we add a referential integrity constraint with a duplicate name, an error occurs. The foreign key object would not have been added to the dictionary cache. In the error path, there is an attempt to remove this foreign key object. Since this object is not there, the search returns a NULL result. De-referencing the null object results in this crash. Solution: If the search to the foreign key object failed, then don't attempt to access it. rb#9309 approved by Marko. --- .../suite/innodb/r/add_constraint.result | 13 ++++++++++++ mysql-test/suite/innodb/t/add_constraint.test | 21 +++++++++++++++++++ storage/innobase/dict/dict0dict.c | 20 ++++++++++++------ 3 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 mysql-test/suite/innodb/r/add_constraint.result create mode 100644 mysql-test/suite/innodb/t/add_constraint.test diff --git a/mysql-test/suite/innodb/r/add_constraint.result b/mysql-test/suite/innodb/r/add_constraint.result new file mode 100644 index 0000000000000..cbbcb4e8fa868 --- /dev/null +++ b/mysql-test/suite/innodb/r/add_constraint.result @@ -0,0 +1,13 @@ +# +# Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE +# +create table t1(a int, b int, key(a),key(b))engine=innodb; +create table t2(a int, b int, key(a),key(b))engine=innodb; +alter table t2 add constraint b foreign key (b) references t1(a); +alter table t1 add constraint b1 foreign key (b) references t2(a); +alter table t2 add constraint b1 foreign key (b) references t1(a); +ERROR HY000: Can't create table '#sql-temporary' (errno: 121) +alter table t2 drop foreign key b; +alter table t1 drop foreign key b1; +drop table t2; +drop table t1; diff --git a/mysql-test/suite/innodb/t/add_constraint.test b/mysql-test/suite/innodb/t/add_constraint.test new file mode 100644 index 0000000000000..eabf06434f4ce --- /dev/null +++ b/mysql-test/suite/innodb/t/add_constraint.test @@ -0,0 +1,21 @@ +--source include/have_innodb.inc + +--echo # +--echo # Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE +--echo # + +create table t1(a int, b int, key(a),key(b))engine=innodb; +create table t2(a int, b int, key(a),key(b))engine=innodb; + +alter table t2 add constraint b foreign key (b) references t1(a); +alter table t1 add constraint b1 foreign key (b) references t2(a); + +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +alter table t2 add constraint b1 foreign key (b) references t1(a); + +alter table t2 drop foreign key b; +alter table t1 drop foreign key b1; + +drop table t2; +drop table t1; diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 56baceb7a4b93..5aca95aec0db8 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -2533,10 +2533,14 @@ dict_foreign_remove_from_cache( if (rbt != NULL && foreign->id != NULL) { const ib_rbt_node_t* node = rbt_lookup(rbt, foreign->id); - dict_foreign_t* val = *(dict_foreign_t**) node->value; - if (val == foreign) { - rbt_delete(rbt, foreign->id); + if (node != NULL) { + dict_foreign_t* val + = *(dict_foreign_t**) node->value; + + if (val == foreign) { + rbt_delete(rbt, foreign->id); + } } } } @@ -2552,10 +2556,14 @@ dict_foreign_remove_from_cache( if (rbt != NULL && foreign->id != NULL) { const ib_rbt_node_t* node = rbt_lookup(rbt, foreign->id); - dict_foreign_t* val = *(dict_foreign_t**) node->value; - if (val == foreign) { - rbt_delete(rbt, foreign->id); + if (node != NULL) { + dict_foreign_t* val + = *(dict_foreign_t**) node->value; + + if (val == foreign) { + rbt_delete(rbt, foreign->id); + } } } } From 00fd99c48465efc5fdf33c4c3f732fcf4a2fd7f5 Mon Sep 17 00:00:00 2001 From: Ajo Robert Date: Mon, 22 Jun 2015 12:09:59 +0530 Subject: [PATCH 22/47] Bug #18075170 SQL NODE RESTART REQUIRED TO AVOID DEADLOCK AFTER RESTORE Post push test fix. --- mysql-test/t/myisam_recover.test | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mysql-test/t/myisam_recover.test b/mysql-test/t/myisam_recover.test index 335c5e34bf0ee..102cd8762a469 100644 --- a/mysql-test/t/myisam_recover.test +++ b/mysql-test/t/myisam_recover.test @@ -124,7 +124,6 @@ connection default; --echo # middle of transaction, without aborting it. connection default; ---let $MYSQL_DATA_DIR=`select @@datadir` create table t1 (a int, key(a)) engine=myisam; create table t2 (a int); @@ -151,7 +150,7 @@ select * from t2; --echo # Without fix select from t1 will break the transaction. After the fix --echo # transaction should be active and should hold lock on table t2. Alter --echo # table from con2 will wait only if the transaction is not broken. ---replace_result $MYSQL_DATA_DIR '' ./ '' test/ '' +--replace_regex /'.*[\/\\]/'/ select * from t1; connect(con2, localhost, root); From 92b4683d59c066f099be1d283c7d61b00caeedb2 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Mon, 22 Jun 2015 12:47:37 +0530 Subject: [PATCH 23/47] Bug #19138298 RECORD IN INDEX WAS NOT FOUND ON ROLLBACK, TRYING TO INSERT Post push fix. The function cmp_dtuple_rec() was used without a prototype in the file row0purge.c. Adding the include file rem0cmp.h to row0purge.c to resolve this issue. approved by Krunal over IM. --- storage/innobase/row/row0purge.c | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index 5e6e6b4ca41aa..9018582f5d6dd 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -43,6 +43,7 @@ Created 3/14/1997 Heikki Tuuri #include "row0vers.h" #include "row0mysql.h" #include "log0log.h" +#include "rem0cmp.h" /************************************************************************* IMPORTANT NOTE: Any operation that generates redo MUST check that there From 830bcff0edd3dd031932e60c7a70fe92a63fc404 Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Thu, 25 Jun 2015 15:04:44 +0200 Subject: [PATCH 24/47] Update docker package names --- packaging/rpm-docker/mysql.spec.in | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packaging/rpm-docker/mysql.spec.in b/packaging/rpm-docker/mysql.spec.in index c5f548ef896f8..5d35fb0a4104f 100644 --- a/packaging/rpm-docker/mysql.spec.in +++ b/packaging/rpm-docker/mysql.spec.in @@ -36,7 +36,7 @@ %global license_type GPLv2 %endif -Name: mysql-%{product_suffix} +Name: mysql-%{product_suffix}-minimal Summary: A very fast and reliable SQL database server Group: Applications/Databases Version: @VERSION@ @@ -79,7 +79,7 @@ The MySQL web site (http://www.mysql.com/) provides the latest news and information about the MySQL software. Also please see the documentation and the manual for more information. -%package server-minimal +%package -n mysql-%{product_suffix}-server-minimal Summary: A very fast and reliable SQL database server Group: Applications/Databases Requires: shadow-utils @@ -88,7 +88,7 @@ Provides: mysql-server%{?_isa} = %{version}-%{release} Provides: mysql-compat-server = %{version}-%{release} Provides: mysql-compat-server%{?_isa} = %{version}-%{release} -%description server-minimal +%description -n mysql-%{product_suffix}-server-minimal The MySQL(TM) software delivers a very fast, multi-threaded, multi-user, and robust SQL (Structured Query Language) database server. MySQL Server is intended for mission-critical, heavy-load production systems as well @@ -209,17 +209,17 @@ pushd mysql-test rm -r $(readlink var) var %endif -%pre server-minimal +%pre -n mysql-%{product_suffix}-server-minimal /usr/sbin/groupadd -g 27 -o -r mysql >/dev/null 2>&1 || : /usr/sbin/useradd -M -N -g mysql -o -r -d /var/lib/mysql -s /bin/false \ -c "MySQL Server" -u 27 mysql >/dev/null 2>&1 || : -%post server-minimal +%post -n mysql-%{product_suffix}-server-minimal /bin/touch /var/log/mysqld.log >/dev/null 2>&1 || : /bin/chmod 0640 /var/log/mysqld.log >/dev/null 2>&1 || : /bin/chown mysql:mysql /var/log/mysqld.log >/dev/null 2>&1 || : -%files server-minimal +%files -n mysql-%{product_suffix}-server-minimal %defattr(-, root, root, -) %doc %{?license_files_server} %doc %{src_dir}/Docs/INFO_SRC* @@ -276,6 +276,9 @@ rm -r $(readlink var) var %dir %attr(750, mysql, mysql) /var/lib/mysql-files %changelog +* Thu Jun 25 2015 Balasubramanian Kandasamy - 5.5.45-1 +- Update package names + * Mon Feb 16 2015 Terje Rosten - 5.5.42-1 - Port to 5.5. From 2e941fe9fce7f1667993916ff3f238a283286d3f Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 25 Jun 2015 23:18:48 +0300 Subject: [PATCH 25/47] Fixed crashing bug when using ONLY_FULL_GROUP_BY in a stored procedure/trigger that is repeatedly executed. This is MDEV-7601, including it's sub tasks MDEV-7594, MDEV-7555, MDEV-7590, MDEV-7581, MDEV-7589 The problem was that select_lex->non_agg_fields was not properly reset for re-execution and this caused an overwrite of a random memory position. The fix was move non_agg_fields from select_lext to JOIN, which is properly reset. --- mysql-test/r/sp-group.result | 156 +++++++++++++++++++++++++++++ mysql-test/t/sp-group.test | 187 +++++++++++++++++++++++++++++++++++ sql/item.cc | 7 +- sql/item.h | 2 +- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 2 - sql/sql_select.cc | 2 +- sql/sql_select.h | 4 + sql/sql_union.cc | 3 +- sql/table.cc | 2 +- 10 files changed, 357 insertions(+), 10 deletions(-) create mode 100644 mysql-test/r/sp-group.result create mode 100644 mysql-test/t/sp-group.test diff --git a/mysql-test/r/sp-group.result b/mysql-test/r/sp-group.result new file mode 100644 index 0000000000000..9744bbee6b654 --- /dev/null +++ b/mysql-test/r/sp-group.result @@ -0,0 +1,156 @@ +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +drop view if exists view_t1; +Warnings: +Note 1051 Unknown table 'test.view_t1' +SET sql_mode=ONLY_FULL_GROUP_BY; +CREATE TABLE t1 ( +pk INT, +f0 INT, f1 INT, f2 INT, f3 INT, f4 INT, +f5 INT, f6 INT, f7 INT, f8 INT, f9 INT, +PRIMARY KEY (pk) +); +CREATE VIEW view_t1 AS SELECT * FROM t1; +CREATE PROCEDURE s1() +SELECT * FROM ( +INFORMATION_SCHEMA.`INNODB_BUFFER_PAGE_LRU` AS table1 +LEFT JOIN test.view_t1 AS table2 +ON ( table2.`f6` = table1.FREE_PAGE_CLOCK) +) +ORDER BY table1.NUMBER_RECORDS +LIMIT 0 +; +CALL s1; +POOL_ID LRU_POSITION SPACE PAGE_NUMBER PAGE_TYPE FLUSH_TYPE FIX_COUNT IS_HASHED NEWEST_MODIFICATION OLDEST_MODIFICATION ACCESS_TIME TABLE_NAME INDEX_NAME NUMBER_RECORDS DATA_SIZE COMPRESSED_SIZE COMPRESSED IO_FIX IS_OLD FREE_PAGE_CLOCK pk f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 +CALL s1; +POOL_ID LRU_POSITION SPACE PAGE_NUMBER PAGE_TYPE FLUSH_TYPE FIX_COUNT IS_HASHED NEWEST_MODIFICATION OLDEST_MODIFICATION ACCESS_TIME TABLE_NAME INDEX_NAME NUMBER_RECORDS DATA_SIZE COMPRESSED_SIZE COMPRESSED IO_FIX IS_OLD FREE_PAGE_CLOCK pk f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 +drop table t1; +drop view view_t1; +drop procedure s1; +CREATE TABLE A ( +pk INTEGER AUTO_INCREMENT, +col_int_key INTEGER, +col_varchar_key VARCHAR(1), +PRIMARY KEY (pk) +) ENGINE=MyISAM; +CREATE VIEW view_A AS SELECT * FROM A; +CREATE TABLE C ( +pk INTEGER AUTO_INCREMENT, +col_int_nokey INTEGER, +col_int_key INTEGER, +col_date_key DATE, +col_date_nokey DATE, +col_time_key TIME, +col_time_nokey TIME, +col_datetime_key DATETIME, +col_datetime_nokey DATETIME, +col_varchar_key VARCHAR(1), +col_varchar_nokey VARCHAR(1), +PRIMARY KEY (pk) +) ENGINE=MyISAM; +CREATE VIEW view_C AS SELECT * FROM C; +CREATE TABLE AA ( +pk INTEGER AUTO_INCREMENT, +col_int_nokey INTEGER, +col_int_key INTEGER, +col_date_key DATE, +col_date_nokey DATE, +col_time_key TIME, +col_time_nokey TIME, +col_datetime_key DATETIME, +col_datetime_nokey DATETIME, +col_varchar_key VARCHAR(1), +col_varchar_nokey VARCHAR(1), +PRIMARY KEY (pk), +KEY (col_varchar_key, col_int_key) +) ENGINE=MyISAM; +CREATE VIEW view_AA AS SELECT * FROM AA; +CREATE TABLE BB ( +pk INTEGER AUTO_INCREMENT, +col_int_key INTEGER, +col_varchar_key VARCHAR(1), +col_varchar_nokey VARCHAR(1), +PRIMARY KEY (pk), +KEY (col_varchar_key, col_int_key) +) ENGINE=MyISAM; +CREATE VIEW view_BB AS SELECT * FROM BB; +CREATE TABLE DD ( +pk INTEGER AUTO_INCREMENT, +col_int_key INTEGER, +col_date_key DATE, +col_time_key TIME, +col_datetime_key DATETIME, +col_varchar_key VARCHAR(1), +PRIMARY KEY (pk), +KEY (col_varchar_key, col_int_key) +) ENGINE=MyISAM; +CREATE VIEW view_DD AS SELECT * FROM DD; +CREATE TRIGGER k BEFORE INSERT ON `DD` FOR EACH ROW INSERT INTO `view_BB` SELECT * FROM `view_A` LIMIT 0 ; +CREATE TRIGGER r BEFORE INSERT ON `A` FOR EACH ROW INSERT INTO `view_AA` SELECT * FROM `view_C` LIMIT 0 ; +ALTER TABLE `DD` DROP PRIMARY KEY; +ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key +INSERT INTO `view_A` ( `pk` ) VALUES (NULL); +INSERT INTO `DD` ( `pk` ) VALUES (NULL); +INSERT INTO `A` ( `pk` ) VALUES (NULL); +INSERT INTO `view_DD` ( `pk` ) VALUES (NULL); +drop trigger r; +drop trigger k; +drop view view_A,view_AA,view_C,view_BB,view_DD; +drop table A,C,AA,BB,DD; +CREATE TABLE A ( +i INT, +i1 INT, +i2 INT, +d1 DATE, +d2 DATE, +col_time_nokey1 TIME, +col_time_nokey2 TIME, +col_datetime_nokey1 DATETIME, +col_datetime_nokey2 DATETIME, +col_varchar_nokey1 VARCHAR(1), +col_varchar_nokey2 VARCHAR(1) +) ENGINE=MyISAM; +CREATE VIEW view_A AS SELECT * FROM A; +CREATE TABLE B ( +col_varchar_nokey VARCHAR(1) +) ENGINE=MyISAM; +CREATE TABLE AA ( +i INT, +i1 INT, +i2 INT, +d1 DATE, +d2 DATE, +col_time_nokey1 TIME, +col_time_nokey2 TIME, +col_datetime_nokey1 DATETIME, +col_datetime_nokey2 DATETIME, +col_varchar_nokey1 VARCHAR(1), +col_varchar_nokey2 VARCHAR(1) +) ENGINE=MyISAM; +CREATE VIEW view_AA AS SELECT * FROM AA; +CREATE TABLE DD ( +i INT, +i1 INT, +i2 INT, +d1 DATE, +d2 DATE, +col_time_nokey1 TIME, +col_time_nokey2 TIME, +col_datetime_nokey1 DATETIME, +col_datetime_nokey2 DATETIME, +col_varchar_nokey1 VARCHAR(1), +col_varchar_nokey2 VARCHAR(1) +) ENGINE=MyISAM; +CREATE VIEW view_DD AS SELECT * FROM DD; +CREATE TRIGGER tr1 BEFORE INSERT ON `AA` FOR EACH ROW INSERT INTO `view_A` SELECT * FROM `view_AA` LIMIT 0 ; +CREATE TRIGGER tr2 BEFORE INSERT ON `B` FOR EACH ROW INSERT INTO `D` SELECT * FROM `A` LIMIT 0 ; +INSERT INTO `view_AA` ( `i` ) VALUES (1); +INSERT INTO `AA` ( `i` ) VALUES (2); +DELETE FROM `B`; +INSERT INTO `view_DD` ( `i` ) VALUES (1); +INSERT INTO `view_AA` ( `i` ) VALUES (3); +drop trigger tr1; +drop trigger tr2; +drop view view_A, view_AA,view_DD; +drop table A,B,AA,DD; diff --git a/mysql-test/t/sp-group.test b/mysql-test/t/sp-group.test new file mode 100644 index 0000000000000..2083ac9759577 --- /dev/null +++ b/mysql-test/t/sp-group.test @@ -0,0 +1,187 @@ +--source include/have_innodb.inc + +drop table if exists t1; +drop view if exists view_t1; + +# +# Test case for MDEV 7601, MDEV-7594 and MDEV-7555 +# Server crashes in functions related to stored procedures +# Server crashes in different ways while executing concurrent +# flow involving views and non-empty sql_mode with ONLY_FULL_GROUP_BY +# + +SET sql_mode=ONLY_FULL_GROUP_BY; + +CREATE TABLE t1 ( + pk INT, + f0 INT, f1 INT, f2 INT, f3 INT, f4 INT, + f5 INT, f6 INT, f7 INT, f8 INT, f9 INT, + PRIMARY KEY (pk) +); + +CREATE VIEW view_t1 AS SELECT * FROM t1; +CREATE PROCEDURE s1() + SELECT * FROM ( + INFORMATION_SCHEMA.`INNODB_BUFFER_PAGE_LRU` AS table1 + LEFT JOIN test.view_t1 AS table2 + ON ( table2.`f6` = table1.FREE_PAGE_CLOCK) + ) + ORDER BY table1.NUMBER_RECORDS + LIMIT 0 +; +CALL s1; +CALL s1; + +drop table t1; +drop view view_t1; +drop procedure s1; + +# +# MDEV-7590 +# Server crashes in st_select_lex_unit::cleanup on executing a trigger +# + +CREATE TABLE A ( + pk INTEGER AUTO_INCREMENT, + col_int_key INTEGER, + col_varchar_key VARCHAR(1), + PRIMARY KEY (pk) +) ENGINE=MyISAM; +CREATE VIEW view_A AS SELECT * FROM A; +CREATE TABLE C ( + pk INTEGER AUTO_INCREMENT, + col_int_nokey INTEGER, + col_int_key INTEGER, + col_date_key DATE, + col_date_nokey DATE, + col_time_key TIME, + col_time_nokey TIME, + col_datetime_key DATETIME, + col_datetime_nokey DATETIME, + col_varchar_key VARCHAR(1), + col_varchar_nokey VARCHAR(1), + PRIMARY KEY (pk) +) ENGINE=MyISAM; +CREATE VIEW view_C AS SELECT * FROM C; +CREATE TABLE AA ( + pk INTEGER AUTO_INCREMENT, + col_int_nokey INTEGER, + col_int_key INTEGER, + col_date_key DATE, + col_date_nokey DATE, + col_time_key TIME, + col_time_nokey TIME, + col_datetime_key DATETIME, + col_datetime_nokey DATETIME, + col_varchar_key VARCHAR(1), + col_varchar_nokey VARCHAR(1), + PRIMARY KEY (pk), + KEY (col_varchar_key, col_int_key) +) ENGINE=MyISAM; +CREATE VIEW view_AA AS SELECT * FROM AA; +CREATE TABLE BB ( + pk INTEGER AUTO_INCREMENT, + col_int_key INTEGER, + col_varchar_key VARCHAR(1), + col_varchar_nokey VARCHAR(1), + PRIMARY KEY (pk), + KEY (col_varchar_key, col_int_key) +) ENGINE=MyISAM; +CREATE VIEW view_BB AS SELECT * FROM BB; +CREATE TABLE DD ( + pk INTEGER AUTO_INCREMENT, + col_int_key INTEGER, + col_date_key DATE, + col_time_key TIME, + col_datetime_key DATETIME, + col_varchar_key VARCHAR(1), + PRIMARY KEY (pk), + KEY (col_varchar_key, col_int_key) +) ENGINE=MyISAM; +CREATE VIEW view_DD AS SELECT * FROM DD; +CREATE TRIGGER k BEFORE INSERT ON `DD` FOR EACH ROW INSERT INTO `view_BB` SELECT * FROM `view_A` LIMIT 0 ; +CREATE TRIGGER r BEFORE INSERT ON `A` FOR EACH ROW INSERT INTO `view_AA` SELECT * FROM `view_C` LIMIT 0 ; +--error ER_WRONG_AUTO_KEY +ALTER TABLE `DD` DROP PRIMARY KEY; +INSERT INTO `view_A` ( `pk` ) VALUES (NULL); +--error 0,ER_WRONG_VALUE_COUNT_ON_ROW +INSERT INTO `DD` ( `pk` ) VALUES (NULL); +INSERT INTO `A` ( `pk` ) VALUES (NULL); +--error 0,ER_WRONG_VALUE_COUNT_ON_ROW +INSERT INTO `view_DD` ( `pk` ) VALUES (NULL); + +drop trigger r; +drop trigger k; +drop view view_A,view_AA,view_C,view_BB,view_DD; +drop table A,C,AA,BB,DD; + +# +# MDEV-7581 +# Server crashes in st_select_lex_unit::cleanup after a sequence of statements +# + +CREATE TABLE A ( + i INT, + i1 INT, + i2 INT, + d1 DATE, + d2 DATE, + col_time_nokey1 TIME, + col_time_nokey2 TIME, + col_datetime_nokey1 DATETIME, + col_datetime_nokey2 DATETIME, + col_varchar_nokey1 VARCHAR(1), + col_varchar_nokey2 VARCHAR(1) +) ENGINE=MyISAM; + +CREATE VIEW view_A AS SELECT * FROM A; + +CREATE TABLE B ( + col_varchar_nokey VARCHAR(1) +) ENGINE=MyISAM; + +CREATE TABLE AA ( + i INT, + i1 INT, + i2 INT, + d1 DATE, + d2 DATE, + col_time_nokey1 TIME, + col_time_nokey2 TIME, + col_datetime_nokey1 DATETIME, + col_datetime_nokey2 DATETIME, + col_varchar_nokey1 VARCHAR(1), + col_varchar_nokey2 VARCHAR(1) +) ENGINE=MyISAM; + +CREATE VIEW view_AA AS SELECT * FROM AA; + +CREATE TABLE DD ( + i INT, + i1 INT, + i2 INT, + d1 DATE, + d2 DATE, + col_time_nokey1 TIME, + col_time_nokey2 TIME, + col_datetime_nokey1 DATETIME, + col_datetime_nokey2 DATETIME, + col_varchar_nokey1 VARCHAR(1), + col_varchar_nokey2 VARCHAR(1) +) ENGINE=MyISAM; + +CREATE VIEW view_DD AS SELECT * FROM DD; + +CREATE TRIGGER tr1 BEFORE INSERT ON `AA` FOR EACH ROW INSERT INTO `view_A` SELECT * FROM `view_AA` LIMIT 0 ; +CREATE TRIGGER tr2 BEFORE INSERT ON `B` FOR EACH ROW INSERT INTO `D` SELECT * FROM `A` LIMIT 0 ; + +INSERT INTO `view_AA` ( `i` ) VALUES (1); +INSERT INTO `AA` ( `i` ) VALUES (2); +DELETE FROM `B`; +INSERT INTO `view_DD` ( `i` ) VALUES (1); +INSERT INTO `view_AA` ( `i` ) VALUES (3); + +drop trigger tr1; +drop trigger tr2; +drop view view_A, view_AA,view_DD; +drop table A,B,AA,DD; diff --git a/sql/item.cc b/sql/item.cc index dbcf1b4cbe114..2f49ae4659673 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4883,7 +4883,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) non aggregated fields of the outer select. */ marker= select->cur_pos_in_select_list; - select->non_agg_fields.push_back(this); + select->join->non_agg_fields.push_back(this); } if (*from_field != view_ref_found) { @@ -5299,9 +5299,10 @@ bool Item_field::fix_fields(THD *thd, Item **reference) fixed= 1; if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !outer_fixed && !thd->lex->in_sum_func && - thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS) + thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS && + thd->lex->current_select->join) { - thd->lex->current_select->non_agg_fields.push_back(this); + thd->lex->current_select->join->non_agg_fields.push_back(this); marker= thd->lex->current_select->cur_pos_in_select_list; } mark_non_agg_field: diff --git a/sql/item.h b/sql/item.h index 4aaa67d9a1d9e..a38a25dfc7578 100644 --- a/sql/item.h +++ b/sql/item.h @@ -631,7 +631,7 @@ class Item { */ uint name_length; /* Length of name */ uint decimals; - int8 marker; + int marker; bool maybe_null; /* If item may be null */ bool in_rollup; /* If used in GROUP BY list of a query with ROLLUP */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1d62acdbe4b41..9ccafa75ca748 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1917,7 +1917,6 @@ void st_select_lex::init_select() with_sum_func= 0; is_correlated= 0; cur_pos_in_select_list= UNDEF_POS; - non_agg_fields.empty(); cond_value= having_value= Item::COND_UNDEF; inner_refs_list.empty(); insert_tables= 0; @@ -1925,6 +1924,7 @@ void st_select_lex::init_select() m_non_agg_field_used= false; m_agg_func_used= false; name_visibility_map= 0; + join= 0; } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a0f8e4568000c..aa59d76245b30 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -877,8 +877,6 @@ class st_select_lex: public st_select_lex_node bool no_wrap_view_item; /* exclude this select from check of unique_table() */ bool exclude_from_table_unique_test; - /* List of fields that aren't under an aggregate function */ - List non_agg_fields; /* index in the select list of the expression currently being fixed */ int cur_pos_in_select_list; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fb7cafc595f85..5ed7a67da6129 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20705,7 +20705,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, Item_field *field; int cur_pos_in_select_list= 0; List_iterator li(fields); - List_iterator naf_it(thd->lex->current_select->non_agg_fields); + List_iterator naf_it(thd->lex->current_select->join->non_agg_fields); field= naf_it++; while (field && (item=li++)) diff --git a/sql/sql_select.h b/sql/sql_select.h index de5baeee1519e..4f807ff5b93c3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -922,6 +922,9 @@ class JOIN :public Sql_alloc Item *pre_sort_idx_pushed_cond; void clean_pre_sort_join_tab(); + /* List of fields that aren't under an aggregate function */ + List non_agg_fields; + /* For "Using temporary+Using filesort" queries, JOIN::join_tab can point to either: @@ -1301,6 +1304,7 @@ class JOIN :public Sql_alloc all_fields= fields_arg; if (&fields_list != &fields_arg) /* Avoid valgrind-warning */ fields_list= fields_arg; + non_agg_fields.empty(); bzero((char*) &keyuse,sizeof(keyuse)); tmp_table_param.init(); tmp_table_param.end_write_records= HA_POS_ERROR; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 6e2e6e06ff7f9..87d3e86b2c7d5 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1021,7 +1021,6 @@ bool st_select_lex::cleanup() { error= (bool) ((uint) error | (uint) lex_unit->cleanup()); } - non_agg_fields.empty(); inner_refs_list.empty(); exclude_from_table_unique_test= FALSE; DBUG_RETURN(error); @@ -1032,6 +1031,7 @@ void st_select_lex::cleanup_all_joins(bool full) { SELECT_LEX_UNIT *unit; SELECT_LEX *sl; + DBUG_ENTER("st_select_lex::cleanup_all_joins"); if (join) join->cleanup(full); @@ -1039,6 +1039,7 @@ void st_select_lex::cleanup_all_joins(bool full) for (unit= first_inner_unit(); unit; unit= unit->next_unit()) for (sl= unit->first_select(); sl; sl= sl->next_select()) sl->cleanup_all_joins(full); + DBUG_VOID_RETURN; } diff --git a/sql/table.cc b/sql/table.cc index e4dee77171d19..f521056aaee08 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5194,7 +5194,7 @@ Item *Field_iterator_table::create_item(THD *thd) if (item && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !thd->lex->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS) { - select->non_agg_fields.push_back(item); + select->join->non_agg_fields.push_back(item); item->marker= select->cur_pos_in_select_list; select->set_non_agg_field_used(true); } From 8c815751c92313dfa45ef0398b609c9988a0a451 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 25 Jun 2015 23:26:29 +0300 Subject: [PATCH 26/47] Problem was that for cases like: SELECT ... WHERE XX IN (SELECT YY) this was transformed to something like: SELECT ... WHERE IF_EXISTS(SELECT ... HAVING XX=YY) The bug was that for normal execution XX was fixed in the original outer SELECT context while in PS it was fixed in the sub query context and this confused the optimizer. Fixed by ensuring that XX is always fixed in the outer context. --- mysql-test/r/subselect_mat.result | 27 +++++++++++++++++++++++++++ mysql-test/r/subselect_sj_mat.result | 27 +++++++++++++++++++++++++++ mysql-test/t/subselect_sj_mat.test | 21 ++++++++++++++++++++- sql/item_subselect.cc | 21 ++++++++++++++++++++- sql/sql_base.cc | 3 +-- sql/sql_select.cc | 12 +++++++----- 6 files changed, 102 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 7039bbfca1500..8c25577eb019d 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -2145,6 +2145,33 @@ drop database mysqltest1; drop database mysqltest2; drop database mysqltest3; drop database mysqltest4; +# +# MDEV-7810 Wrong result on execution of a query as a PS +# (both 1st and further executions) +CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES (0),(8); +SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2; +a +0 +8 +SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a)); +MIN(t3.a) +0 +SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq +WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ); +a +0 +PREPARE stmt FROM " +SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq +WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ) +"; +execute stmt; +a +0 +execute stmt; +a +0 +drop table t1; # End of 5.5 tests set @subselect_mat_test_optimizer_switch_value=null; set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off'; diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 58810670395f1..6c69d195bd33b 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -2185,4 +2185,31 @@ drop database mysqltest1; drop database mysqltest2; drop database mysqltest3; drop database mysqltest4; +# +# MDEV-7810 Wrong result on execution of a query as a PS +# (both 1st and further executions) +CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES (0),(8); +SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2; +a +0 +8 +SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a)); +MIN(t3.a) +0 +SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq +WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ); +a +0 +PREPARE stmt FROM " +SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq +WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ) +"; +execute stmt; +a +0 +execute stmt; +a +0 +drop table t1; # End of 5.5 tests diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index 912e9d5befdcc..63c72f20e2135 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1841,5 +1841,24 @@ drop database mysqltest2; drop database mysqltest3; drop database mysqltest4; ---echo # End of 5.5 tests +--echo # +--echo # MDEV-7810 Wrong result on execution of a query as a PS +--echo # (both 1st and further executions) + +CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES (0),(8); + +SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2; +SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a)); +SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq +WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ); +PREPARE stmt FROM " +SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq +WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ) +"; +execute stmt; +execute stmt; +drop table t1; + +--echo # End of 5.5 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 62df666b71fa7..8b0c6efc9ee72 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1999,12 +1999,31 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN * join, during JOIN::optimize: this->tmp_having= this->having; this->having= 0; */ Item* join_having= join->having ? join->having : join->tmp_having; - DBUG_ENTER("Item_in_subselect::create_single_in_to_exists_cond"); *where_item= NULL; *having_item= NULL; + /* + For PS we have to do fix_fields(expr) here to ensure that it's + evaluated in the outer context. If not, then fix_having() will do + a fix_fields(expr) in the inner context and mark expr as + 'depended', which will cause update_ref_and_keys() to find wrong + keys. + When not running PS, fix_fields(expr) as already been done earlier and + the following test does nothing. + */ + if (expr && !expr->fixed) + { + SELECT_LEX *save_current_select= thd->lex->current_select; + thd->lex->current_select= thd->lex->current_select->outer_select(); + bool tmp; + tmp= expr->fix_fields(thd, 0); + thd->lex->current_select= save_current_select; + if (tmp) + DBUG_RETURN(true); + } + if (join_having || select_lex->with_sum_func || select_lex->group_list.elements) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fcd17b25b2d7b..aefa82405ff78 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6859,6 +6859,7 @@ find_field_in_tables(THD *thd, Item_ident *item, if (item->cached_table) { + DBUG_PRINT("info", ("using cached table")); /* This shortcut is used by prepared statements. We assume that TABLE_LIST *first_table is not changed during query execution (which @@ -6935,8 +6936,6 @@ find_field_in_tables(THD *thd, Item_ident *item, return found; } } - else - item->can_be_depended= TRUE; if (db && lower_case_table_names) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5ed7a67da6129..e542b08f911b0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4904,6 +4904,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, KEY_FIELD *key_fields, *end, *field; uint sz; uint m= max(select_lex->max_equal_elems,1); + DBUG_ENTER("update_ref_and_keys"); + DBUG_PRINT("enter", ("normal_tables: %llx", normal_tables)); SELECT_LEX *sel=thd->lex->current_select; sel->cond_count= 0; @@ -4950,7 +4952,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))* ((sel->cond_count*2 + sel->between_count)*m+1); if (!(key_fields=(KEY_FIELD*) thd->alloc(sz))) - return TRUE; /* purecov: inspected */ + DBUG_RETURN(TRUE); /* purecov: inspected */ and_level= 0; field= end= key_fields; *sargables= (SARGABLE_PARAM *) key_fields + @@ -4959,7 +4961,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, (*sargables)[0].field= 0; if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64)) - return TRUE; + DBUG_RETURN(TRUE); if (cond) { @@ -5009,16 +5011,16 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, for ( ; field != end ; field++) { if (add_key_part(keyuse,field)) - return TRUE; + DBUG_RETURN(TRUE); } if (select_lex->ftfunc_list->elements) { if (add_ft_keys(keyuse,join_tab,cond,normal_tables)) - return TRUE; + DBUG_RETURN(TRUE); } - return FALSE; + DBUG_RETURN(FALSE); } From 67c56ab1e4841058c40e6b61e1dcbb6e21d4ce52 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 25 Jun 2015 23:34:54 +0300 Subject: [PATCH 27/47] Simple cleanups - Removing use of calls to current_thd - More DBUG_PRINT - Code style changes - Made some local functions static Ensure that calls to print_keyuse are locked with mutex to get all lines in same debug packet --- sql/item.cc | 27 ++++++++++++++++----------- sql/item_subselect.cc | 5 ++++- sql/sql_test.cc | 7 ++----- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 2f49ae4659673..9b3e9a546c6bf 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4415,18 +4415,23 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, Item_ident *resolved_item, Item_ident *mark_item) { - const char *db_name= (resolved_item->db_name ? - resolved_item->db_name : ""); - const char *table_name= (resolved_item->table_name ? - resolved_item->table_name : ""); + DBUG_ENTER("mark_as_dependent"); + /* store pointer on SELECT_LEX from which item is dependent */ if (mark_item && mark_item->can_be_depended) + { + DBUG_PRINT("info", ("mark_item: %p lex: %p", mark_item, last)); mark_item->depended_from= last; - if (current->mark_as_dependent(thd, last, /** resolved_item psergey-thu - **/mark_item)) - return TRUE; + } + if (current->mark_as_dependent(thd, last, + /** resolved_item psergey-thu **/ mark_item)) + DBUG_RETURN(TRUE); if (thd->lex->describe & DESCRIBE_EXTENDED) { + const char *db_name= (resolved_item->db_name ? + resolved_item->db_name : ""); + const char *table_name= (resolved_item->table_name ? + resolved_item->table_name : ""); push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_WARN_FIELD_RESOLVED, ER(ER_WARN_FIELD_RESOLVED), db_name, (db_name[0] ? "." : ""), @@ -4434,7 +4439,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, resolved_item->field_name, current->select_number, last->select_number); } - return FALSE; + DBUG_RETURN(FALSE); } @@ -6886,7 +6891,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) { /* The current reference cannot be resolved in this query. */ my_error(ER_BAD_FIELD_ERROR,MYF(0), - this->full_name(), current_thd->where); + this->full_name(), thd->where); goto error; } @@ -7021,7 +7026,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) goto error; thd->change_item_tree(reference, fld); mark_as_dependent(thd, last_checked_context->select_lex, - thd->lex->current_select, fld, fld); + current_sel, fld, fld); /* A reference is resolved to a nest level that's outer or the same as the nest level of the enclosing set function : adjust the value of @@ -7038,7 +7043,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) { /* The item was not a table field and not a reference */ my_error(ER_BAD_FIELD_ERROR, MYF(0), - this->full_name(), current_thd->where); + this->full_name(), thd->where); goto error; } /* Should be checked in resolve_ref_in_select_and_group(). */ diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8b0c6efc9ee72..d31f7b8e5cb0d 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -464,6 +464,7 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent, { List_iterator it(upper_refs); Ref_to_outside *upper; + DBUG_ENTER("recalc_used_tables"); used_tables_cache= 0; while ((upper= it++)) @@ -523,6 +524,8 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent, he has done const table detection, and that will be our chance to update const_tables_cache. */ + DBUG_PRINT("exit", ("used_tables_cache: %llx", used_tables_cache)); + DBUG_VOID_RETURN; } @@ -1989,7 +1992,7 @@ bool Item_allany_subselect::is_maxmin_applicable(JOIN *join) */ bool -Item_in_subselect::create_single_in_to_exists_cond(JOIN * join, +Item_in_subselect::create_single_in_to_exists_cond(JOIN *join, Item **where_item, Item **having_item) { diff --git a/sql/sql_test.cc b/sql/sql_test.cc index ec426e39ee35e..dc6bc8187ffc8 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -248,7 +248,7 @@ TEST_join(JOIN *join) #define FT_KEYPART (MAX_REF_PARTS+10) -void print_keyuse(KEYUSE *keyuse) +static void print_keyuse(KEYUSE *keyuse) { char buff[256]; char buf2[64]; @@ -266,14 +266,11 @@ void print_keyuse(KEYUSE *keyuse) else fieldname= key_info->key_part[keyuse->keypart].field->field_name; ll2str(keyuse->used_tables, buf2, 16, 0); - DBUG_LOCK_FILE; fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s optimize: %u used_tables: %s " "ref_table_rows: %lu keypart_map: %0lx\n", keyuse->table->alias.c_ptr(), fieldname, str.ptr(), (uint) keyuse->optimize, buf2, (ulong) keyuse->ref_table_rows, (ulong) keyuse->keypart_map); - DBUG_UNLOCK_FILE; - //key_part_map keypart_map; --?? there can be several? } @@ -282,9 +279,9 @@ void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array) { DBUG_LOCK_FILE; fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements); - DBUG_UNLOCK_FILE; for(uint i=0; i < keyuse_array->elements; i++) print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i)); + DBUG_UNLOCK_FILE; } From bc300464f1674dc774fd166a87d8894cbe498563 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 26 Jun 2015 14:48:22 +0300 Subject: [PATCH 28/47] Fix for MDEV-8301; Statistics for a thread could be counted twice in SHOW STATUS while thread was ending Fixed by adding a marker if we have added the thread statistics to the global counters. --- sql/sql_class.cc | 2 ++ sql/sql_class.h | 11 ++++++++--- sql/sql_show.cc | 5 ++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 76b2031f553d9..a4a4b37065809 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1263,6 +1263,7 @@ void THD::init(void) bzero((char *) &status_var, sizeof(status_var)); bzero((char *) &org_status_var, sizeof(org_status_var)); start_bytes_received= 0; + status_in_global= 0; if (variables.sql_log_bin) variables.option_bits|= OPTION_BIN_LOG; @@ -1366,6 +1367,7 @@ void THD::change_user(void) cleanup(); reset_killed(); cleanup_done= 0; + status_in_global= 0; init(); stmt_map.reset(); my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, diff --git a/sql/sql_class.h b/sql/sql_class.h index 67db1662f107c..17dd0f9f64f56 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1733,11 +1733,11 @@ class THD :public Statement, /* Do not set socket timeouts for wait_timeout (used with threadpool) */ bool skip_wait_timeout; - /* container for handler's private per-connection data */ - Ha_data ha_data[MAX_HA]; - bool prepare_derived_at_open; + /* Set to 1 if status of this THD is already in global status */ + bool status_in_global; + /* To signal that the tmp table to be created is created for materialized derived table or a view. @@ -1746,6 +1746,9 @@ class THD :public Statement, bool save_prep_leaf_list; + /* container for handler's private per-connection data */ + Ha_data ha_data[MAX_HA]; + #ifndef MYSQL_CLIENT binlog_cache_mngr * binlog_setup_trx_data(); @@ -3116,6 +3119,8 @@ class THD :public Statement, { mysql_mutex_lock(&LOCK_status); add_to_status(&global_status_var, &status_var); + /* Mark that this THD status has already been added in global status */ + status_in_global= 1; mysql_mutex_unlock(&LOCK_status); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 22484748523b7..1e27e65431809 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3109,7 +3109,10 @@ void calc_sum_of_all_status(STATUS_VAR *to) /* Add to this status from existing threads */ while ((tmp= it++)) - add_to_status(to, &tmp->status_var); + { + if (!tmp->status_in_global) + add_to_status(to, &tmp->status_var); + } mysql_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; From 44de090a5fdcf799d826226055ee848af653e375 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 17 Jul 2015 00:02:25 +0300 Subject: [PATCH 29/47] MDEV-8432 Slave cannot replicate signed integer-type values with high bit set to 1 The fix is that if the slave has a different integer size than the master, then they will assume the master has the same signed/unsigned modifier as the slave. This means that one can safely change a coon the slave an int to a bigint or an unsigned int to an unsigned int. Changing an unsigned int to an signed bigint will cause replication failures when the high bit of the unsigned int is set. We can't give an error if the signess is different on the master and slave as the binary log doesn't contain the signess of the column on the master. --- mysql-test/suite/rpl/r/rpl_alter.result | 105 ++++++++++++++++++++++++ mysql-test/suite/rpl/t/rpl_alter.test | 53 ++++++++++++ 2 files changed, 158 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_alter.result b/mysql-test/suite/rpl/r/rpl_alter.result index 2cffa70d778e6..7be3bc576f34b 100644 --- a/mysql-test/suite/rpl/r/rpl_alter.result +++ b/mysql-test/suite/rpl/r/rpl_alter.result @@ -14,4 +14,109 @@ select * from mysqltest.t3; n 45 drop database mysqltest; +use test; +# +# Test bug where ALTER TABLE MODIFY didn't replicate properly +# +create table t1 (a int unsigned primary key, b int); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(10) unsigned NOT NULL, + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 (a) values (1),((1<<32)-1); +select * from t1; +a b +1 NULL +4294967295 NULL +alter table t1 modify a bigint; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t1; +a b +1 NULL +4294967295 NULL +alter table t1 modify a int unsigned; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(10) unsigned NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t1; +a b +1 NULL +4294967295 NULL +alter table t1 modify a bigint unsigned; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) unsigned NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t1; +a b +1 NULL +4294967295 NULL +use test; +select * from t1; +a b +1 NULL +4294967295 NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) unsigned NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +create table t2 (a int unsigned auto_increment primary key, b int); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(10) unsigned NOT NULL AUTO_INCREMENT, + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t2 modify a bigint; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` bigint(20) NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t2 modify a bigint auto_increment; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1,t2; +# +# MDEV-8432: Slave cannot replicate signed integer-type values +# with high bit set to 1 +# Test replication when we have int on master and bigint on slave +# +create table t1 (a int unsigned primary key, b int); +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +alter table t1 modify a bigint unsigned; +insert into t1 (a) values (1),((1<<32)-1); +select * from t1; +a b +1 NULL +4294967295 NULL +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +drop table t1; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_alter.test b/mysql-test/suite/rpl/t/rpl_alter.test index 630197f8637bc..8b8bcfb3d26f5 100644 --- a/mysql-test/suite/rpl/t/rpl_alter.test +++ b/mysql-test/suite/rpl/t/rpl_alter.test @@ -15,4 +15,57 @@ drop database mysqltest; sync_slave_with_master; # End of 4.1 tests + +connection master; +use test; + +--echo # +--echo # Test bug where ALTER TABLE MODIFY didn't replicate properly +--echo # + +create table t1 (a int unsigned primary key, b int); +show create table t1; +insert into t1 (a) values (1),((1<<32)-1); +select * from t1; +alter table t1 modify a bigint; +show create table t1; +select * from t1; +alter table t1 modify a int unsigned; +show create table t1; +select * from t1; +alter table t1 modify a bigint unsigned; +show create table t1; +select * from t1; +sync_slave_with_master; +use test; +select * from t1; +show create table t1; +connection master; +# +create table t2 (a int unsigned auto_increment primary key, b int); +show create table t2; +alter table t2 modify a bigint; +show create table t2; +alter table t2 modify a bigint auto_increment; +show create table t2; +drop table t1,t2; + +--echo # +--echo # MDEV-8432: Slave cannot replicate signed integer-type values +--echo # with high bit set to 1 +--echo # Test replication when we have int on master and bigint on slave +--echo # + +create table t1 (a int unsigned primary key, b int); +sync_slave_with_master; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +alter table t1 modify a bigint unsigned; +connection master; +insert into t1 (a) values (1),((1<<32)-1); +sync_slave_with_master; +select * from t1; +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +connection master; +drop table t1; + --source include/rpl_end.inc From 00d3b20fbb669840daebf2a4483cead92221d78c Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 17 Jul 2015 00:06:27 +0300 Subject: [PATCH 30/47] MDEV-8432 Slave cannot replicate signed integer-type values with high bit set to 1 The fix is that if the slave has a different integer size than the master, then they will assume the master has the same signed/unsigned modifier as the slave. This means that one can safely change a coon the slave an int to a bigint or an unsigned int to an unsigned int. Changing an unsigned int to an signed bigint will cause replication failures when the high bit of the unsigned int is set. We can't give an error if the signess is different on the master and slave as the binary log doesn't contain the signess of the column on the master. --- mysql-test/suite/rpl/r/rpl_alter.result | 105 ++++++++++++++++++++++++ mysql-test/suite/rpl/t/rpl_alter.test | 53 ++++++++++++ sql/rpl_utility.cc | 21 ++++- 3 files changed, 175 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_alter.result b/mysql-test/suite/rpl/r/rpl_alter.result index 2cffa70d778e6..7be3bc576f34b 100644 --- a/mysql-test/suite/rpl/r/rpl_alter.result +++ b/mysql-test/suite/rpl/r/rpl_alter.result @@ -14,4 +14,109 @@ select * from mysqltest.t3; n 45 drop database mysqltest; +use test; +# +# Test bug where ALTER TABLE MODIFY didn't replicate properly +# +create table t1 (a int unsigned primary key, b int); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(10) unsigned NOT NULL, + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 (a) values (1),((1<<32)-1); +select * from t1; +a b +1 NULL +4294967295 NULL +alter table t1 modify a bigint; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t1; +a b +1 NULL +4294967295 NULL +alter table t1 modify a int unsigned; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(10) unsigned NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t1; +a b +1 NULL +4294967295 NULL +alter table t1 modify a bigint unsigned; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) unsigned NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t1; +a b +1 NULL +4294967295 NULL +use test; +select * from t1; +a b +1 NULL +4294967295 NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) unsigned NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +create table t2 (a int unsigned auto_increment primary key, b int); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(10) unsigned NOT NULL AUTO_INCREMENT, + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t2 modify a bigint; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` bigint(20) NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t2 modify a bigint auto_increment; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1,t2; +# +# MDEV-8432: Slave cannot replicate signed integer-type values +# with high bit set to 1 +# Test replication when we have int on master and bigint on slave +# +create table t1 (a int unsigned primary key, b int); +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +alter table t1 modify a bigint unsigned; +insert into t1 (a) values (1),((1<<32)-1); +select * from t1; +a b +1 NULL +4294967295 NULL +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +drop table t1; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_alter.test b/mysql-test/suite/rpl/t/rpl_alter.test index 630197f8637bc..8b8bcfb3d26f5 100644 --- a/mysql-test/suite/rpl/t/rpl_alter.test +++ b/mysql-test/suite/rpl/t/rpl_alter.test @@ -15,4 +15,57 @@ drop database mysqltest; sync_slave_with_master; # End of 4.1 tests + +connection master; +use test; + +--echo # +--echo # Test bug where ALTER TABLE MODIFY didn't replicate properly +--echo # + +create table t1 (a int unsigned primary key, b int); +show create table t1; +insert into t1 (a) values (1),((1<<32)-1); +select * from t1; +alter table t1 modify a bigint; +show create table t1; +select * from t1; +alter table t1 modify a int unsigned; +show create table t1; +select * from t1; +alter table t1 modify a bigint unsigned; +show create table t1; +select * from t1; +sync_slave_with_master; +use test; +select * from t1; +show create table t1; +connection master; +# +create table t2 (a int unsigned auto_increment primary key, b int); +show create table t2; +alter table t2 modify a bigint; +show create table t2; +alter table t2 modify a bigint auto_increment; +show create table t2; +drop table t1,t2; + +--echo # +--echo # MDEV-8432: Slave cannot replicate signed integer-type values +--echo # with high bit set to 1 +--echo # Test replication when we have int on master and bigint on slave +--echo # + +create table t1 (a int unsigned primary key, b int); +sync_slave_with_master; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +alter table t1 modify a bigint unsigned; +connection master; +insert into t1 (a) values (1),((1<<32)-1); +sync_slave_with_master; +select * from t1; +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +connection master; +drop table t1; + --source include/rpl_end.inc diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index e05ad5a8d43d4..9a20f71f4f751 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -876,6 +876,7 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE * { Create_field *field_def= (Create_field*) alloc_root(thd->mem_root, sizeof(Create_field)); + bool unsigned_flag= 0; if (field_list.push_back(field_def)) DBUG_RETURN(NULL); @@ -885,8 +886,7 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE * uint32 max_length= max_display_length_for_field(type(col), field_metadata(col)); - switch(type(col)) - { + switch(type(col)) { int precision; case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: @@ -925,6 +925,18 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE * pack_length= field_metadata(col) & 0x00ff; break; + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + /* + As we don't know if the integer was signed or not on the master, + assume we have same sign on master and slave. This is true when not + using conversions so it should be true also when using conversions. + */ + unsigned_flag= ((Field_num*) target_table->field[col])->unsigned_flag; + break; default: break; } @@ -932,12 +944,13 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE * DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d," " maybe_null: %d, unsigned_flag: %d, pack_length: %u", type(col), target_table->field[col]->field_name, - max_length, decimals, TRUE, FALSE, pack_length)); + max_length, decimals, TRUE, unsigned_flag, + pack_length)); field_def->init_for_tmp_table(type(col), max_length, decimals, TRUE, // maybe_null - FALSE, // unsigned_flag + unsigned_flag, pack_length); field_def->charset= target_table->field[col]->charset(); field_def->interval= interval; From 7a9670218b2d1b5673432ebf4e0f028a7c963494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 21 Jul 2015 12:12:58 +0300 Subject: [PATCH 31/47] MDEV-8474: InnoDB sets per-connection data unsafely Analysis: At check_trx_exists function InnoDB allocates a new trx if no trx is found from thd but this newly allocated trx is not registered to thd. This is unsafe, because nothing prevents InnoDB plugin from being uninstalled while there's active transaction. This can cause crashes, hang and any other odd behavior. It may also corrupt stack, as functions pointers are not available after dlclose. Fix: The fix is to use thd_set_ha_data() when manipulating per-connection handler data. It does appropriate plugin locking. --- mysql-test/mysql-test-run.pl | 1 + mysql-test/r/innodb_load_xa.result | 2 + .../suite/innodb/r/innodb_uninstall.result | 22 +++++++ .../suite/innodb/t/innodb_uninstall.opt | 3 + .../suite/innodb/t/innodb_uninstall.test | 58 +++++++++++++++++++ mysql-test/t/innodb_load_xa.test | 3 + storage/innobase/handler/ha_innodb.cc | 1 + storage/xtradb/handler/ha_innodb.cc | 1 + 8 files changed, 91 insertions(+) create mode 100644 mysql-test/suite/innodb/r/innodb_uninstall.result create mode 100644 mysql-test/suite/innodb/t/innodb_uninstall.opt create mode 100644 mysql-test/suite/innodb/t/innodb_uninstall.test diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 566423a1c07cf..26b31d34d3c9e 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -4806,6 +4806,7 @@ ($$) qr|Plugin 'FEEDBACK' registration as a INFORMATION SCHEMA failed|, qr|Failed to setup SSL|, qr|SSL error: Failed to set ciphers to use|, + qr/Plugin 'InnoDB' will be forced to shutdown/, ); my $matched_lines= []; diff --git a/mysql-test/r/innodb_load_xa.result b/mysql-test/r/innodb_load_xa.result index e738ca6e3afb9..8b8de2032e545 100644 --- a/mysql-test/r/innodb_load_xa.result +++ b/mysql-test/r/innodb_load_xa.result @@ -18,3 +18,5 @@ mysqld-bin.000001 # Query # # use `test`; insert t1 values (2) mysqld-bin.000001 # Query # # COMMIT drop table t1; uninstall plugin innodb; +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown diff --git a/mysql-test/suite/innodb/r/innodb_uninstall.result b/mysql-test/suite/innodb/r/innodb_uninstall.result new file mode 100644 index 0000000000000..2064269a02e3f --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_uninstall.result @@ -0,0 +1,22 @@ +install plugin innodb soname 'ha_innodb'; +create table t1(a int not null primary key) engine=innodb; +begin; +insert into t1 values(1); +flush tables; +uninstall plugin innodb; +select sleep(1); +sleep(1) +0 +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown +drop table t1; +install plugin innodb soname 'ha_innodb'; +create table t2(a int not null primary key) engine=innodb; +insert into t2 values(1); +drop table t2; +uninstall plugin innodb; +select sleep(1); +sleep(1) +0 +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown diff --git a/mysql-test/suite/innodb/t/innodb_uninstall.opt b/mysql-test/suite/innodb/t/innodb_uninstall.opt new file mode 100644 index 0000000000000..918855a7b0169 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_uninstall.opt @@ -0,0 +1,3 @@ +--ignore-builtin-innodb +--loose-innodb + diff --git a/mysql-test/suite/innodb/t/innodb_uninstall.test b/mysql-test/suite/innodb/t/innodb_uninstall.test new file mode 100644 index 0000000000000..34fc8345a02ad --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_uninstall.test @@ -0,0 +1,58 @@ +--source include/not_embedded.inc +--source include/not_windows.inc + +if (!$HA_INNODB_SO) { + --skip Need InnoDB plugin +} + +# +# MDEV-8474: InnoDB sets per-connection data unsafely +# Below test caused hang +# +install plugin innodb soname 'ha_innodb'; +create table t1(a int not null primary key) engine=innodb; + +connect (con1, localhost, root); +connection con1; +begin; +insert into t1 values(1); + +connection default; +flush tables; +send uninstall plugin innodb; + +connection con1; +select sleep(1); +disconnect con1; + +connection default; +reap; + +--source include/restart_mysqld.inc + +drop table t1; + +# +# Another test that caused hang. +# + +connect (con1, localhost, root); +connection con1; +install plugin innodb soname 'ha_innodb'; +create table t2(a int not null primary key) engine=innodb; +insert into t2 values(1); +drop table t2; + +connection default; +send uninstall plugin innodb; + +connection con1; +select sleep(1); +disconnect con1; + +connection default; +reap; + +--source include/restart_mysqld.inc + + diff --git a/mysql-test/t/innodb_load_xa.test b/mysql-test/t/innodb_load_xa.test index 52862151b22d9..9ecddde5d1301 100644 --- a/mysql-test/t/innodb_load_xa.test +++ b/mysql-test/t/innodb_load_xa.test @@ -16,3 +16,6 @@ commit; --source include/show_binlog_events.inc drop table t1; uninstall plugin innodb; + +--source include/restart_mysqld.inc + diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7c17f20ce406e..c97b5bfadc251 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1597,6 +1597,7 @@ check_trx_exists( if (trx == NULL) { trx = innobase_trx_allocate(thd); + thd_set_ha_data(thd, innodb_hton_ptr, trx); } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) { mem_analyze_corruption(trx); ut_error; diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 5034e7e70e15b..fa0081da436c6 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -1853,6 +1853,7 @@ check_trx_exists( if (trx == NULL) { trx = innobase_trx_allocate(thd); + thd_set_ha_data(thd, innodb_hton_ptr, trx); } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) { mem_analyze_corruption(trx); ut_error; From 7115341473947882994a5857db8113f7b08a516f Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 23 Jul 2015 14:57:12 +0300 Subject: [PATCH 32/47] Fixed warnings and errors found by buildbot field.cc - Fixed warning about overlapping memory copy (backport from 10.0) Item_subselect.cc - Fixed core dump in main.view - Problem was that thd->lex->current_select->master_unit()->item was not set, which caused crash in maxr_as_dependent sql/mysqld.cc - Got error on shutdown as we where freeing mutex before all THD objects was freed (~THD uses some mutex). Fixed by during shutdown freeing THD inside mutex. sql/log.cc - log_space_lock and LOCK_log where locked in inconsistenly. Fixed by not having a log_space_lock around purge_logs. sql/slave.cc - Remove unnecessary log_space_lock - Move cond_broadcast inside lock to ensure we don't miss the signal --- sql/field.cc | 3 ++- sql/item_subselect.cc | 13 ++++++++++++- sql/log.cc | 33 +++++++++++++++------------------ sql/mysqld.cc | 11 ++++++++++- sql/slave.cc | 10 +--------- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index a24ffe286004e..aeeacf7f88da9 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7612,7 +7612,8 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) } Field_blob::store_length(length); - if (table->copy_blobs || length <= MAX_FIELD_WIDTH) + if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) && + from != value.ptr()) { // Must make a copy value.copy(from, length, cs); from= value.ptr(); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index d31f7b8e5cb0d..3b280c4560811 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2018,10 +2018,21 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join, */ if (expr && !expr->fixed) { + bool tmp; SELECT_LEX *save_current_select= thd->lex->current_select; + Item_subselect *save_item; + thd->lex->current_select= thd->lex->current_select->outer_select(); - bool tmp; + /* + For st_select_lex::mark_as_dependent, who needs to mark + this sub query as correlated. + */ + save_item= thd->lex->current_select->master_unit()->item; + thd->lex->current_select->master_unit()->item= this; + tmp= expr->fix_fields(thd, 0); + + thd->lex->current_select->master_unit()->item= save_item; thd->lex->current_select= save_current_select; if (tmp) DBUG_RETURN(true); diff --git a/sql/log.cc b/sql/log.cc index 9722f20869da7..0940cb9b56c6e 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3676,6 +3676,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) { int error; char *to_purge_if_included= NULL; + ulonglong log_space_reclaimed= 0; DBUG_ENTER("purge_first_log"); DBUG_ASSERT(is_open()); @@ -3724,17 +3725,13 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included) DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE();); - mysql_mutex_lock(&rli->log_space_lock); rli->relay_log.purge_logs(to_purge_if_included, included, - 0, 0, &rli->log_space_total); - mysql_mutex_unlock(&rli->log_space_lock); + 0, 0, &log_space_reclaimed); - /* - Ok to broadcast after the critical region as there is no risk of - the mutex being destroyed by this thread later - this helps save - context switches - */ + mysql_mutex_lock(&rli->log_space_lock); + rli->log_space_total-= log_space_reclaimed; mysql_cond_broadcast(&rli->log_space_cond); + mysql_mutex_unlock(&rli->log_space_lock); /* * Need to update the log pos because purge logs has been called @@ -3783,8 +3780,8 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads @param need_mutex @param need_update_threads If we want to update the log coordinates of all threads. False for relay logs, true otherwise. - @param freed_log_space If not null, decrement this variable of - the amount of log space freed + @param reclaimeed_log_space If not null, increment this variable to + the amount of log space freed @note If any of the logs before the deleted one is in use, @@ -3800,10 +3797,10 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads */ int MYSQL_BIN_LOG::purge_logs(const char *to_log, - bool included, - bool need_mutex, - bool need_update_threads, - ulonglong *decrease_log_space) + bool included, + bool need_mutex, + bool need_update_threads, + ulonglong *reclaimed_space) { int error= 0; bool exit_loop= 0; @@ -3868,7 +3865,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, err: /* Read each entry from purge_index_file and delete the file. */ if (is_inited_purge_index_file() && - (error= purge_index_entry(thd, decrease_log_space, FALSE))) + (error= purge_index_entry(thd, reclaimed_space, FALSE))) sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files" " that would be purged."); close_purge_index_file(); @@ -3973,7 +3970,7 @@ int MYSQL_BIN_LOG::register_create_index_entry(const char *entry) DBUG_RETURN(register_purge_index_entry(entry)); } -int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space, +int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *reclaimed_space, bool need_mutex) { DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry"); @@ -4093,8 +4090,8 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space, DBUG_PRINT("info",("purging %s",log_info.log_file_name)); if (!my_delete(log_info.log_file_name, MYF(0))) { - if (decrease_log_space) - *decrease_log_space-= s.st_size; + if (reclaimed_space) + *reclaimed_space+= s.st_size; } else { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0178f927baba1..1f741bf0a6534 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2488,7 +2488,6 @@ void unlink_thd(THD *thd) thd->add_status_to_global(); mysql_mutex_lock(&LOCK_thread_count); - thread_count--; thd->unlink(); /* Used by binlog_reset_master. It would be cleaner to use @@ -2496,6 +2495,16 @@ void unlink_thd(THD *thd) sync feature has been shut down at this point. */ DBUG_EXECUTE_IF("sleep_after_lock_thread_count_before_delete_thd", sleep(5);); + if (unlikely(abort_loop)) + { + /* + During shutdown, we have to delete thd inside the mutex + to not refer to mutexes that may be deleted during shutdown + */ + delete thd; + thd= 0; + } + thread_count--; mysql_mutex_unlock(&LOCK_thread_count); delete thd; diff --git a/sql/slave.cc b/sql/slave.cc index 2fe7ebb575d2e..fe96b1de008fc 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3556,9 +3556,7 @@ pthread_handler_t handle_slave_sql(void *arg) rli->clear_error(); //tell the I/O thread to take relay_log_space_limit into account from now on - mysql_mutex_lock(&rli->log_space_lock); rli->ignore_log_space_limit= 0; - mysql_mutex_unlock(&rli->log_space_lock); rli->trans_retries= 0; // start from "no error" DBUG_PRINT("info", ("rli->trans_retries: %lu", rli->trans_retries)); @@ -5228,14 +5226,8 @@ static Log_event* next_event(Relay_log_info* rli) rli->ignore_log_space_limit= true; } - /* - If the I/O thread is blocked, unblock it. Ok to broadcast - after unlock, because the mutex is only destroyed in - ~Relay_log_info(), i.e. when rli is destroyed, and rli will - not be destroyed before we exit the present function. - */ - mysql_mutex_unlock(&rli->log_space_lock); mysql_cond_broadcast(&rli->log_space_cond); + mysql_mutex_unlock(&rli->log_space_lock); // Note that wait_for_update_relay_log unlocks lock_log ! rli->relay_log.wait_for_update_relay_log(rli->sql_thd); // re-acquire data lock since we released it earlier From e40bc659335f7f8b69427ed2d215c34c045a5ed7 Mon Sep 17 00:00:00 2001 From: Monty Date: Sat, 25 Jul 2015 15:14:40 +0300 Subject: [PATCH 33/47] Fixed memory loss detected on P8. This can happen when we call after_flush but never call after_rollback() or after_commit(). The old code used pthread_setspecific() to store temporary data used by the thread. This is not safe when used with thread pool, as the thread may change for the transaction. The fix is to save the data in THD, which is guaranteed to be properly freed. I also fixed the code so that we don't do a malloc() for every transaction. --- sql/rpl_handler.cc | 54 +++++++++++++++++++--------------------------- sql/sql_class.cc | 2 ++ sql/sql_class.h | 5 ++++- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc index 9480a9e0454f8..5b75d6c30eaad 100644 --- a/sql/rpl_handler.cc +++ b/sql/rpl_handler.cc @@ -38,8 +38,6 @@ typedef struct Trans_binlog_info { char log_file[FN_REFLEN]; } Trans_binlog_info; -static pthread_key(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); - int get_user_var_int(const char *name, long long int *value, int *null_value) { @@ -143,13 +141,6 @@ int delegates_init() } #endif - if (pthread_key_create(&RPL_TRANS_BINLOG_INFO, NULL)) - { - sql_print_error("Error while creating pthread specific data key for replication. " - "Please report a bug."); - return 1; - } - return 0; } @@ -195,27 +186,27 @@ void delegates_destroy() int Trans_delegate::after_commit(THD *thd, bool all) { Trans_param param; + Trans_binlog_info *log_info; bool is_real_trans= (all || thd->transaction.all.ha_list == 0); + int ret= 0; param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; - Trans_binlog_info *log_info= - my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); + log_info= thd->semisync_info; - param.log_file= log_info ? log_info->log_file : 0; + param.log_file= log_info && log_info->log_file[0] ? log_info->log_file : 0; param.log_pos= log_info ? log_info->log_pos : 0; - int ret= 0; FOREACH_OBSERVER(ret, after_commit, false, (¶m)); /* This is the end of a real transaction or autocommit statement, we - can free the memory allocated for binlog file and position. + can mark the memory unused. */ if (is_real_trans && log_info) { - my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL); - my_free(log_info); + log_info->log_file[0]= 0; + log_info->log_pos= 0; } return ret; } @@ -223,27 +214,27 @@ int Trans_delegate::after_commit(THD *thd, bool all) int Trans_delegate::after_rollback(THD *thd, bool all) { Trans_param param; + Trans_binlog_info *log_info; bool is_real_trans= (all || thd->transaction.all.ha_list == 0); + int ret= 0; param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; - Trans_binlog_info *log_info= - my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); - - param.log_file= log_info ? log_info->log_file : 0; + log_info= thd->semisync_info; + + param.log_file= log_info && log_info->log_file[0] ? log_info->log_file : 0; param.log_pos= log_info ? log_info->log_pos : 0; - int ret= 0; FOREACH_OBSERVER(ret, after_rollback, false, (¶m)); /* This is the end of a real transaction or autocommit statement, we - can free the memory allocated for binlog file and position. + can mark the memory unused. */ if (is_real_trans && log_info) { - my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL); - my_free(log_info); + log_info->log_file[0]= 0; + log_info->log_pos= 0; } return ret; } @@ -254,25 +245,24 @@ int Binlog_storage_delegate::after_flush(THD *thd, bool synced) { Binlog_storage_param param; + Trans_binlog_info *log_info; uint32 flags=0; + int ret= 0; + if (synced) flags |= BINLOG_STORAGE_IS_SYNCED; - Trans_binlog_info *log_info= - my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); - - if (!log_info) + if (!(log_info= thd->semisync_info)) { if(!(log_info= - (Trans_binlog_info *)my_malloc(sizeof(Trans_binlog_info), MYF(0)))) + (Trans_binlog_info*) my_malloc(sizeof(Trans_binlog_info), MYF(0)))) return 1; - my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, log_info); + thd->semisync_info= log_info; } - + strcpy(log_info->log_file, log_file+dirname_length(log_file)); log_info->log_pos = log_pos; - int ret= 0; FOREACH_OBSERVER(ret, after_flush, false, (¶m, log_info->log_file, log_info->log_pos, flags)); return ret; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a4a4b37065809..7b97d5839fc6d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -877,6 +877,7 @@ THD::THD() file_id = 0; query_id= 0; query_name_consts= 0; + semisync_info= 0; db_charset= global_system_variables.collation_database; bzero(ha_data, sizeof(ha_data)); mysys_var=0; @@ -1493,6 +1494,7 @@ THD::~THD() mysql_audit_free_thd(this); if (rli_slave) rli_slave->cleanup_after_session(); + my_free(semisync_info); #endif free_root(&main_mem_root, MYF(0)); diff --git a/sql/sql_class.h b/sql/sql_class.h index 17dd0f9f64f56..8d51120e428ed 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -47,7 +47,6 @@ class Reprepare_observer; class Relay_log_info; - class Query_log_event; class Load_log_event; class Slave_log_event; @@ -59,6 +58,7 @@ class Rows_log_event; class Sroutine_hash_entry; class User_level_lock; class user_var_entry; +class Trans_binlog_info; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME }; @@ -1670,6 +1670,9 @@ class THD :public Statement, */ const char *where; + /* Needed by MariaDB semi sync replication */ + Trans_binlog_info *semisync_info; + ulong client_capabilities; /* What the client supports */ ulong max_client_packet_length; From 392df76bc3a40a5dd1956b12628dd6489a37be36 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 23 Jul 2015 12:50:58 +0400 Subject: [PATCH 34/47] MDEV-4017 - GET_LOCK() with negative timeouts has strange behavior GET_LOCK() silently accepted negative values and NULL for timeout. Fixed GET_LOCK() to issue a warning and return NULL in such cases. --- .../binlog_tests/mix_innodb_myisam_binlog.test | 2 +- mysql-test/r/func_misc.result | 13 +++++++++++++ .../r/binlog_row_mix_innodb_myisam.result | 2 +- .../r/binlog_stm_mix_innodb_myisam.result | 4 ++-- mysql-test/t/func_misc.test | 5 +++++ sql/item_func.cc | 18 ++++++++++++++++++ 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test index b41bfeaba7467..336b11113ec3c 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test @@ -228,7 +228,7 @@ rollback; create table t0 (n int); insert t0 select * from t1; set autocommit=1; -insert into t0 select GET_LOCK("lock1",null); +insert into t0 select GET_LOCK("lock1",0); set autocommit=0; create table t2 (n int) engine=innodb; insert into t2 values (3); diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index d5db28f04b8c6..d654dbccb0e2b 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -361,5 +361,18 @@ set optimizer_switch=@optimizer_switch_save; drop view v_merge, vm; drop table t1,tv; # +# MDEV-4017 - GET_LOCK() with negative timeouts has strange behavior +# +SELECT GET_LOCK('ul1', NULL); +GET_LOCK('ul1', NULL) +NULL +Warnings: +Warning 1411 Incorrect timeout value: 'NULL' for function get_lock +SELECT GET_LOCK('ul1', -1); +GET_LOCK('ul1', -1) +NULL +Warnings: +Warning 1411 Incorrect timeout value: '-1' for function get_lock +# # End of 5.5 tests # diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index ac36412c360fd..ed6e711af6b7b 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -258,7 +258,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back create table t0 (n int); insert t0 select * from t1; set autocommit=1; -insert into t0 select GET_LOCK("lock1",null); +insert into t0 select GET_LOCK("lock1",0); set autocommit=0; create table t2 (n int) engine=innodb; insert into t2 values (3); diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index c10aa7abd0500..7309c611d298c 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -242,7 +242,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back create table t0 (n int); insert t0 select * from t1; set autocommit=1; -insert into t0 select GET_LOCK("lock1",null); +insert into t0 select GET_LOCK("lock1",0); Warnings: Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. set autocommit=0; @@ -288,7 +288,7 @@ master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; insert t0 select * from t1 master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `test`; insert into t0 select GET_LOCK("lock1",null) +master-bin.000001 # Query # # use `test`; insert into t0 select GET_LOCK("lock1",0) master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; create table t2 (n int) engine=innodb master-bin.000001 # Query # # use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `t1`,`ti` diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 24fe1ef79844f..25d8cc1067ac6 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -391,6 +391,11 @@ set optimizer_switch=@optimizer_switch_save; drop view v_merge, vm; drop table t1,tv; +--echo # +--echo # MDEV-4017 - GET_LOCK() with negative timeouts has strange behavior +--echo # +SELECT GET_LOCK('ul1', NULL); +SELECT GET_LOCK('ul1', -1); --echo # --echo # End of 5.5 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index ed08555133f6d..2f5130886e69a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4184,7 +4184,25 @@ longlong Item_func_get_lock::val_int() it's not guaranteed to be same as on master. */ if (thd->slave_thread) + { + null_value= 0; DBUG_RETURN(1); + } + + if (args[1]->null_value || + (!args[1]->unsigned_flag && ((longlong) timeout < 0))) + { + char buf[22]; + if (args[1]->null_value) + strmov(buf, "NULL"); + else + llstr(((longlong) timeout), buf); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE), + "timeout", buf, "get_lock"); + null_value= 1; + DBUG_RETURN(0); + } mysql_mutex_lock(&LOCK_user_locks); From e05cd97b8af6ebda0080eec40018207d0c78acbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 29 Jul 2015 05:58:45 +0300 Subject: [PATCH 35/47] MDEV-8524: Improve error messaging when there is duplicate key or foreign key names Added better error message that will be printed when foreign key constraint name in create table is not unique in database. --- .../suite/innodb/r/innodb-fk-warnings.result | 20 +++ .../suite/innodb/t/innodb-fk-warnings.test | 29 +++++ storage/innobase/dict/dict0crea.c | 117 +++++++++++++++++- storage/innobase/handler/ha_innodb.cc | 26 ++++ storage/innobase/include/ha_prototypes.h | 9 ++ storage/xtradb/dict/dict0crea.c | 117 +++++++++++++++++- storage/xtradb/handler/ha_innodb.cc | 25 ++++ storage/xtradb/include/ha_prototypes.h | 9 ++ 8 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/innodb/r/innodb-fk-warnings.result create mode 100644 mysql-test/suite/innodb/t/innodb-fk-warnings.test diff --git a/mysql-test/suite/innodb/r/innodb-fk-warnings.result b/mysql-test/suite/innodb/r/innodb-fk-warnings.result new file mode 100644 index 0000000000000..c64cb3024b513 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb-fk-warnings.result @@ -0,0 +1,20 @@ +CREATE TABLE t1 ( +id int(11) NOT NULL PRIMARY KEY, +a int(11) NOT NULL, +b int(11) NOT NULL, +c int not null, +CONSTRAINT test FOREIGN KEY (b) REFERENCES t1 (id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +CREATE TABLE t2 ( +id int(11) NOT NULL PRIMARY KEY, +a int(11) NOT NULL, +b int(11) NOT NULL, +c int not null, +CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +ERROR HY000: Can't create table 'test.t2' (errno: 121) +show warnings; +Level Code Message +Warning 121 InnoDB: foreign key constraint name `test/test` already exists on data dictionary. Foreign key constraint names need to be unique in database. Error in foreign key definition: CONSTRAINT `test` FOREIGN KEY (`b`) REFERENCES `test`.`t2` (`id`). +Error 1005 Can't create table 'test.t2' (errno: 121) +drop table t1; diff --git a/mysql-test/suite/innodb/t/innodb-fk-warnings.test b/mysql-test/suite/innodb/t/innodb-fk-warnings.test new file mode 100644 index 0000000000000..e12a0ecf820a3 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-fk-warnings.test @@ -0,0 +1,29 @@ +--source include/have_innodb.inc + +# +# MDEV-8524: Improve error messaging when there is duplicate key or foreign key names +# +CREATE TABLE t1 ( + id int(11) NOT NULL PRIMARY KEY, + a int(11) NOT NULL, + b int(11) NOT NULL, + c int not null, + CONSTRAINT test FOREIGN KEY (b) REFERENCES t1 (id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +# +# Below create table fails because constraint name test +# is reserved for above table. +# +--error 1005 +CREATE TABLE t2 ( + id int(11) NOT NULL PRIMARY KEY, + a int(11) NOT NULL, + b int(11) NOT NULL, + c int not null, + CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +show warnings; + +drop table t1; diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index ac8a1eac03cf7..7a52aff3ec3c1 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -1419,6 +1419,91 @@ dict_create_add_foreign_field_to_dictionary( table, foreign, trx)); } +/********************************************************************//** +Construct foreign key constraint defintion from data dictionary information. +*/ +static +char* +dict_foreign_def_get( + dict_foreign_t* foreign,/*!< in: foreign */ + trx_t* trx) /*!< in: trx */ +{ + char* fk_def = mem_heap_alloc(foreign->heap, 4*1024); + const char* tbname; + char tablebuf[MAX_TABLE_NAME_LEN + 1] = ""; + int i; + + tbname = dict_remove_db_name(foreign->id); + innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + tbname, strlen(tbname), trx->mysql_thd, FALSE); + + sprintf(fk_def, + (char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf); + + for(i = 0; i < foreign->n_fields; i++) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->foreign_col_names[i], + strlen(foreign->foreign_col_names[i]), + trx->mysql_thd, FALSE); + strcat(fk_def, buf); + if (i < foreign->n_fields-1) { + strcat(fk_def, (char *)","); + } + } + + strcat(fk_def,(char *)") REFERENCES "); + + innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + foreign->referenced_table_name, + strlen(foreign->referenced_table_name), + trx->mysql_thd, TRUE); + + strcat(fk_def, tablebuf); + strcat(fk_def, " ("); + + for(i = 0; i < foreign->n_fields; i++) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->referenced_col_names[i], + strlen(foreign->referenced_col_names[i]), + trx->mysql_thd, FALSE); + strcat(fk_def, buf); + if (i < foreign->n_fields-1) { + strcat(fk_def, (char *)","); + } + } + strcat(fk_def, (char *)")"); + + return fk_def; +} + +/********************************************************************//** +Convert foreign key column names from data dictionary to SQL-layer. +*/ +static +void +dict_foreign_def_get_fields( + dict_foreign_t* foreign,/*!< in: foreign */ + trx_t* trx, /*!< in: trx */ + char** field, /*!< out: foreign column */ + char** field2, /*!< out: referenced column */ + int col_no) /*!< in: column number */ +{ + *field = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + *field2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + + innobase_convert_name(*field, MAX_TABLE_NAME_LEN, + foreign->foreign_col_names[col_no], + strlen(foreign->foreign_col_names[col_no]), + trx->mysql_thd, FALSE); + + innobase_convert_name(*field, MAX_TABLE_NAME_LEN, + foreign->referenced_col_names[col_no], + strlen(foreign->referenced_col_names[col_no]), + trx->mysql_thd, FALSE); +} + /********************************************************************//** Add a single foreign key definition to the data dictionary tables in the database. We also generate names to constraints that were not named by the @@ -1501,6 +1586,22 @@ dict_create_add_foreign_to_dictionary( if (error != DB_SUCCESS) { + if (error == DB_DUPLICATE_KEY) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char* fk_def; + + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); + + fk_def = dict_foreign_def_get(foreign, trx); + + ib_push_warning(trx, error, (const char *)"InnoDB: foreign key constraint name %s " + "already exists on data dictionary." + " Foreign key constraint names need to be unique in database." + " Error in foreign key definition: %s.", + buf, fk_def); + } + return(error); } @@ -1509,6 +1610,20 @@ dict_create_add_foreign_to_dictionary( i, table, foreign, trx); if (error != DB_SUCCESS) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char* field=NULL; + char* field2=NULL; + char* fk_def; + + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); + fk_def = dict_foreign_def_get(foreign, trx); + dict_foreign_def_get_fields(foreign, trx, &field, &field2, i); + + ib_push_warning(trx, error, + (const char *)"InnoDB: Error adding foreign key constraint name %s fields %s or %s to the dictionary." + " Error in foreign key definition: %s.", + buf, i+1, fk_def); return(error); } @@ -1593,7 +1708,7 @@ dict_create_add_foreigns_to_dictionary( foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { error = dict_create_add_foreign_to_dictionary(&number, table, - foreign, trx); + foreign, trx); if (error != DB_SUCCESS) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c97b5bfadc251..2bdbdf7a19f8f 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -12304,3 +12304,29 @@ ib_warn_row_too_big(const dict_table_t* table) " ROW_FORMAT=COMPRESSED ": "" , prefix ? DICT_MAX_FIXED_COL_LEN : 0); } + +/********************************************************************//** +Helper function to push warnings from InnoDB internals to SQL-layer. */ +extern "C" UNIV_INTERN +void +ib_push_warning( + trx_t* trx, /*!< in: trx */ + ulint error, /*!< in: error code to push as warning */ + const char *format,/*!< in: warning message */ + ...) +{ + va_list args; + THD *thd = (THD *)trx->mysql_thd; + char *buf; +#define MAX_BUF_SIZE 4*1024 + + va_start(args, format); + buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); + vsprintf(buf,format, args); + + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + convert_error_code_to_mysql(error, 0, thd), + buf); + my_free(buf); + va_end(args); +} diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 3859b45e8d112..a69d3d126a0af 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -326,5 +326,14 @@ innobase_convert_to_filename_charset( const char* from, /* in: identifier to convert */ ulint len); /* in: length of 'to', in bytes */ +/********************************************************************//** +Helper function to push warnings from InnoDB internals to SQL-layer. */ +UNIV_INTERN +void +ib_push_warning( + trx_t* trx, /*!< in: trx */ + ulint error, /*!< in: error code to push as warning */ + const char *format,/*!< in: warning message */ + ...); #endif diff --git a/storage/xtradb/dict/dict0crea.c b/storage/xtradb/dict/dict0crea.c index c88979b20f964..71a00ca8d0fc9 100644 --- a/storage/xtradb/dict/dict0crea.c +++ b/storage/xtradb/dict/dict0crea.c @@ -1626,6 +1626,91 @@ dict_create_add_foreign_field_to_dictionary( table, foreign, trx)); } +/********************************************************************//** +Construct foreign key constraint defintion from data dictionary information. +*/ +static +char* +dict_foreign_def_get( + dict_foreign_t* foreign,/*!< in: foreign */ + trx_t* trx) /*!< in: trx */ +{ + char* fk_def = mem_heap_alloc(foreign->heap, 4*1024); + const char* tbname; + char tablebuf[MAX_TABLE_NAME_LEN + 1] = ""; + int i; + + tbname = dict_remove_db_name(foreign->id); + innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + tbname, strlen(tbname), trx->mysql_thd, FALSE); + + sprintf(fk_def, + (char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf); + + for(i = 0; i < foreign->n_fields; i++) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->foreign_col_names[i], + strlen(foreign->foreign_col_names[i]), + trx->mysql_thd, FALSE); + strcat(fk_def, buf); + if (i < foreign->n_fields-1) { + strcat(fk_def, (char *)","); + } + } + + strcat(fk_def,(char *)") REFERENCES "); + + innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + foreign->referenced_table_name, + strlen(foreign->referenced_table_name), + trx->mysql_thd, TRUE); + + strcat(fk_def, tablebuf); + strcat(fk_def, " ("); + + for(i = 0; i < foreign->n_fields; i++) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->referenced_col_names[i], + strlen(foreign->referenced_col_names[i]), + trx->mysql_thd, FALSE); + strcat(fk_def, buf); + if (i < foreign->n_fields-1) { + strcat(fk_def, (char *)","); + } + } + strcat(fk_def, (char *)")"); + + return fk_def; +} + +/********************************************************************//** +Convert foreign key column names from data dictionary to SQL-layer. +*/ +static +void +dict_foreign_def_get_fields( + dict_foreign_t* foreign,/*!< in: foreign */ + trx_t* trx, /*!< in: trx */ + char** field, /*!< out: foreign column */ + char** field2, /*!< out: referenced column */ + int col_no) /*!< in: column number */ +{ + *field = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + *field2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + + innobase_convert_name(*field, MAX_TABLE_NAME_LEN, + foreign->foreign_col_names[col_no], + strlen(foreign->foreign_col_names[col_no]), + trx->mysql_thd, FALSE); + + innobase_convert_name(*field, MAX_TABLE_NAME_LEN, + foreign->referenced_col_names[col_no], + strlen(foreign->referenced_col_names[col_no]), + trx->mysql_thd, FALSE); +} + /********************************************************************//** Add a single foreign key definition to the data dictionary tables in the database. We also generate names to constraints that were not named by the @@ -1708,6 +1793,22 @@ dict_create_add_foreign_to_dictionary( if (error != DB_SUCCESS) { + if (error == DB_DUPLICATE_KEY) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char* fk_def; + + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); + + fk_def = dict_foreign_def_get(foreign, trx); + + ib_push_warning(trx, error, (const char *)"InnoDB: foreign key constraint name %s " + "already exists on data dictionary." + " Foreign key constraint names need to be unique in database." + " Error in foreign key definition: %s.", + buf, fk_def); + } + return(error); } @@ -1716,6 +1817,20 @@ dict_create_add_foreign_to_dictionary( i, table, foreign, trx); if (error != DB_SUCCESS) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char* field=NULL; + char* field2=NULL; + char* fk_def; + + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); + fk_def = dict_foreign_def_get(foreign, trx); + dict_foreign_def_get_fields(foreign, trx, &field, &field2, i); + + ib_push_warning(trx, error, + (const char *)"InnoDB: Error adding foreign key constraint name %s fields %s or %s to the dictionary." + " Error in foreign key definition: %s.", + buf, i+1, fk_def); return(error); } @@ -1800,7 +1915,7 @@ dict_create_add_foreigns_to_dictionary( foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { error = dict_create_add_foreign_to_dictionary(&number, table, - foreign, trx); + foreign, trx); if (error != DB_SUCCESS) { diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index fa0081da436c6..6c4e9eedd7de8 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -14107,3 +14107,28 @@ ha_innobase::idx_cond_push( DBUG_RETURN(NULL); } +/********************************************************************//** +Helper function to push warnings from InnoDB internals to SQL-layer. */ +extern "C" UNIV_INTERN +void +ib_push_warning( + trx_t* trx, /*!< in: trx */ + ulint error, /*!< in: error code to push as warning */ + const char *format,/*!< in: warning message */ + ...) +{ + va_list args; + THD *thd = (THD *)trx->mysql_thd; + char *buf; +#define MAX_BUF_SIZE 4*1024 + + va_start(args, format); + buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); + vsprintf(buf,format, args); + + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + convert_error_code_to_mysql(error, 0, thd), + buf); + my_free(buf); + va_end(args); +} diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index ec2ba77f7849c..ad0abb88ff6a5 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -353,5 +353,14 @@ innobase_convert_to_filename_charset( const char* from, /* in: identifier to convert */ ulint len); /* in: length of 'to', in bytes */ +/********************************************************************//** +Helper function to push warnings from InnoDB internals to SQL-layer. */ +UNIV_INTERN +void +ib_push_warning( + trx_t* trx, /*!< in: trx */ + ulint error, /*!< in: error code to push as warning */ + const char *format,/*!< in: warning message */ + ...); #endif From fa765a45250176d1168ce5a61dee484c997604b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2015 08:52:24 +0300 Subject: [PATCH 36/47] MDEV-6697: Improve foreign keys warnings/errors There is several different ways to incorrectly define foreign key constraint. In many cases earlier MariaDB versions the error messages produced by these cases are not very clear and helpful. This patch improves the warning messages produced by foreign key parsing. --- .../suite/innodb/r/innodb-fk-warnings.result | 87 ++- mysql-test/suite/innodb/r/innodb-fk.result | 3 + .../suite/innodb/t/innodb-fk-warnings.test | 101 ++++ storage/innobase/dict/dict0crea.c | 27 +- storage/innobase/dict/dict0dict.c | 516 +++++++++++++++--- storage/innobase/include/dict0crea.h | 11 + storage/xtradb/dict/dict0crea.c | 27 +- storage/xtradb/dict/dict0dict.c | 516 +++++++++++++++--- storage/xtradb/include/dict0crea.h | 11 + 9 files changed, 1132 insertions(+), 167 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-fk-warnings.result b/mysql-test/suite/innodb/r/innodb-fk-warnings.result index c64cb3024b513..542fc972880b6 100644 --- a/mysql-test/suite/innodb/r/innodb-fk-warnings.result +++ b/mysql-test/suite/innodb/r/innodb-fk-warnings.result @@ -10,11 +10,96 @@ id int(11) NOT NULL PRIMARY KEY, a int(11) NOT NULL, b int(11) NOT NULL, c int not null, +CONSTRAINT mytest FOREIGN KEY (c) REFERENCES t1(id), CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ERROR HY000: Can't create table 'test.t2' (errno: 121) show warnings; Level Code Message -Warning 121 InnoDB: foreign key constraint name `test/test` already exists on data dictionary. Foreign key constraint names need to be unique in database. Error in foreign key definition: CONSTRAINT `test` FOREIGN KEY (`b`) REFERENCES `test`.`t2` (`id`). +Warning 121 Create or Alter table `test`.`t2` with foreign key constraint failed. Foreign key constraint `test/test` already exists on data dictionary. Foreign key constraint names need to be unique in database. Error in foreign key definition: CONSTRAINT `test` FOREIGN KEY (`b`) REFERENCES `test`.`t2` (`id`). Error 1005 Can't create table 'test.t2' (errno: 121) drop table t1; +create table t1(a int) engine=innodb; +create table t2(a int, constraint a foreign key a (a) references t1(a)) engine=innodb; +ERROR HY000: Can't create table 'test.t2' (errno: 150) +show warnings; +Level Code Message +Warning 150 Create table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. Error close to foreign key a (a) references t1(a)) engine=innodb. +Error 1005 Can't create table 'test.t2' (errno: 150) +drop table t1; +create table t1(a int not null primary key, b int) engine=innodb; +create table t2(a int, b int, constraint a foreign key a (a) references t1(a), +constraint a foreign key a (a) references t1(b)) engine=innodb; +ERROR HY000: Can't create table 'test.t2' (errno: 150) +show warnings; +Level Code Message +Warning 150 Create table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. Error close to foreign key a (a) references t1(b)) engine=innodb. +Error 1005 Can't create table 'test.t2' (errno: 150) +create table t2(a int, b int, constraint a foreign key a (a) references t1(a)) engine=innodb; +alter table t2 add constraint b foreign key (b) references t2(b); +ERROR HY000: Can't create table '#sql-temporary' (errno: 150) +show warnings; +Level Code Message +Warning 150 Alter table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. Error close to foreign key (b) references t2(b). +Error 1005 Can't create table '#sql-temporary' (errno: 150) +drop table t2, t1; +create table t1 (f1 integer primary key) engine=innodb; +alter table t1 add constraint c1 foreign key (f1) references t11(f1); +ERROR HY000: Can't create table '#sql-temporary' (errno: 150) +show warnings; +Level Code Message +Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Referenced table `test`.`t11` not found in the data dictionary close to foreign key (f1) references t11(f1). +Error 1005 Can't create table '#sql-temporary' (errno: 150) +drop table t1; +create temporary table t1(a int not null primary key, b int, key(b)) engine=innodb; +create temporary table t2(a int, foreign key(a) references t1(a)) engine=innodb; +ERROR HY000: Can't create table 'test.t2' (errno: 150) +show warnings; +Level Code Message +Warning 150 Create table `mysqld.1`.`t2` with foreign key constraint failed. Referenced table `mysqld.1`.`t1` not found in the data dictionary close to foreign key(a) references t1(a)) engine=innodb. +Error 1005 Can't create table 'test.t2' (errno: 150) +alter table t1 add foreign key(b) references t1(a); +ERROR HY000: Can't create table '#sql-temporary' (errno: 150) +show warnings; +Level Code Message +Warning 150 Alter table `mysqld.1`.`t1` with foreign key constraint failed. Referenced table `mysqld.1`.`t1` not found in the data dictionary close to foreign key(b) references t1(a). +Error 1005 Can't create table '#sql-temporary' (errno: 150) +drop table t1; +create table t1(a int not null primary key, b int, key(b)) engine=innodb; +alter table t1 add foreign key(a,b) references t1(a); +ERROR HY000: Can't create table '#sql-temporary' (errno: 150) +show warnings; +Level Code Message +Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Foreign key constraint parse error in foreign key(a,b) references t1(a) close to ). Too few referenced columns, you have 1 when you should have 2. +Error 1005 Can't create table '#sql-temporary' (errno: 150) +drop table t1; +create table t1(a int not null primary key, b int, key(b)) engine=innodb; +alter table t1 add foreign key(a) references t1(a,b); +ERROR HY000: Can't create table '#sql-temporary' (errno: 150) +show warnings; +Level Code Message +Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Foreign key constraint parse error in foreign key(a) references t1(a,b) close to ). Too few referenced columns, you have 2 when you should have 1. +Error 1005 Can't create table '#sql-temporary' (errno: 150) +drop table t1; +create table t1 (f1 integer not null primary key) engine=innodb; +alter table t1 add constraint c1 foreign key (f1) references t1(f1) on update set null; +ERROR HY000: Can't create table '#sql-temporary' (errno: 150) +show warnings; +Level Code Message +Warning 150 Alter table `test`.`t1` with foreign key constraint failed. You have defined a SET NULL condition but column f1 is defined as NOT NULL in foreign key (f1) references t1(f1) on update set null close to on update set null. +Error 1005 Can't create table '#sql-temporary' (errno: 150) +create table t2(a int not null, foreign key(a) references t1(f1) on delete set null) engine=innodb; +ERROR HY000: Can't create table 'test.t2' (errno: 150) +show warnings; +Level Code Message +Warning 150 Create table `test`.`t2` with foreign key constraint failed. You have defined a SET NULL condition but column a is defined as NOT NULL in foreign key(a) references t1(f1) on delete set null) engine=innodb close to on delete set null) engine=innodb. +Error 1005 Can't create table 'test.t2' (errno: 150) +drop table t1; +create table t1 (id int not null primary key, f1 int, f2 int, key(f1)) engine=innodb; +create table t2(a char(20), key(a), foreign key(a) references t1(f1)) engine=innodb; +ERROR HY000: Can't create table 'test.t2' (errno: 150) +show warnings; +Level Code Message +Warning 150 Create table `test`.`t2` with foreign key constraint failed. Field type or character set for column a does not mach referenced column f1 close to foreign key(a) references t1(f1)) engine=innodb +Error 1005 Can't create table 'test.t2' (errno: 150) +drop table t1; diff --git a/mysql-test/suite/innodb/r/innodb-fk.result b/mysql-test/suite/innodb/r/innodb-fk.result index 3c557534dbdf5..2b53bc21b3120 100644 --- a/mysql-test/suite/innodb/r/innodb-fk.result +++ b/mysql-test/suite/innodb/r/innodb-fk.result @@ -50,6 +50,8 @@ CONSTRAINT fk3 FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE CASCADE ERROR HY000: Can't create table 'test.t2' (errno: 150) show warnings; Level Code Message +Warning 150 Create table `test`.`t2` with foreign key constraint failed. Referenced table `test`.`t3` not found in the data dictionary close to FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE CASCADE +) ENGINE=InnoDB. Error 1005 Can't create table 'test.t2' (errno: 150) CREATE TABLE t2 ( id int(11) NOT NULL AUTO_INCREMENT, @@ -62,6 +64,7 @@ ALTER TABLE t2 ADD CONSTRAINT fk3 FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE ERROR HY000: Can't create table '#sql-temporary' (errno: 150) show warnings; Level Code Message +Warning 150 Alter table `test`.`t2` with foreign key constraint failed. Referenced table `test`.`t3` not found in the data dictionary close to FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE CASCADE. Error 1005 Can't create table '#sql-temporary' (errno: 150) drop table t2; drop table t1; diff --git a/mysql-test/suite/innodb/t/innodb-fk-warnings.test b/mysql-test/suite/innodb/t/innodb-fk-warnings.test index e12a0ecf820a3..fe92f1345f41a 100644 --- a/mysql-test/suite/innodb/t/innodb-fk-warnings.test +++ b/mysql-test/suite/innodb/t/innodb-fk-warnings.test @@ -21,9 +21,110 @@ CREATE TABLE t2 ( a int(11) NOT NULL, b int(11) NOT NULL, c int not null, + CONSTRAINT mytest FOREIGN KEY (c) REFERENCES t1(id), CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; show warnings; drop table t1; + +# +# MDEV-6697: Improve foreign keys warnings/errors +# + +# +# No index for referenced columns +# +create table t1(a int) engine=innodb; +--error 1005 +create table t2(a int, constraint a foreign key a (a) references t1(a)) engine=innodb; +show warnings; +drop table t1; + +create table t1(a int not null primary key, b int) engine=innodb; +--error 1005 +create table t2(a int, b int, constraint a foreign key a (a) references t1(a), +constraint a foreign key a (a) references t1(b)) engine=innodb; +show warnings; +create table t2(a int, b int, constraint a foreign key a (a) references t1(a)) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error 1005 +alter table t2 add constraint b foreign key (b) references t2(b); +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; +drop table t2, t1; + +# +# Referenced table does not exists +# + +create table t1 (f1 integer primary key) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error 1005 +alter table t1 add constraint c1 foreign key (f1) references t11(f1); +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; +drop table t1; + +# +# Foreign key on temporal tables +# + +create temporary table t1(a int not null primary key, b int, key(b)) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error 1005 +create temporary table t2(a int, foreign key(a) references t1(a)) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error 1005 +alter table t1 add foreign key(b) references t1(a); +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; +drop table t1; + +# +# Column numbers do not match +# +create table t1(a int not null primary key, b int, key(b)) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error 1005 +alter table t1 add foreign key(a,b) references t1(a); +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; +drop table t1; +create table t1(a int not null primary key, b int, key(b)) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error 1005 +alter table t1 add foreign key(a) references t1(a,b); +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; +drop table t1; + +# +# ON UPDATE/DELETE SET NULL on NOT NULL column +# +create table t1 (f1 integer not null primary key) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error 1005 +alter table t1 add constraint c1 foreign key (f1) references t1(f1) on update set null; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error 1005 +create table t2(a int not null, foreign key(a) references t1(f1) on delete set null) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; +drop table t1; + +# +# Incorrect types +# +create table t1 (id int not null primary key, f1 int, f2 int, key(f1)) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error 1005 +create table t2(a char(20), key(a), foreign key(a) references t1(f1)) engine=innodb; +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; +drop table t1; diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 7a52aff3ec3c1..87fbd4626976f 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -1422,9 +1422,10 @@ dict_create_add_foreign_field_to_dictionary( /********************************************************************//** Construct foreign key constraint defintion from data dictionary information. */ -static +UNIV_INTERN char* dict_foreign_def_get( +/*=================*/ dict_foreign_t* foreign,/*!< in: foreign */ trx_t* trx) /*!< in: trx */ { @@ -1484,6 +1485,7 @@ Convert foreign key column names from data dictionary to SQL-layer. static void dict_foreign_def_get_fields( +/*========================*/ dict_foreign_t* foreign,/*!< in: foreign */ trx_t* trx, /*!< in: trx */ char** field, /*!< out: foreign column */ @@ -1588,18 +1590,25 @@ dict_create_add_foreign_to_dictionary( if (error == DB_DUPLICATE_KEY) { char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char tablename[MAX_TABLE_NAME_LEN + 1] = ""; char* fk_def; + innobase_convert_name(tablename, MAX_TABLE_NAME_LEN, + table->name, strlen(table->name), + trx->mysql_thd, TRUE); + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); fk_def = dict_foreign_def_get(foreign, trx); - ib_push_warning(trx, error, (const char *)"InnoDB: foreign key constraint name %s " - "already exists on data dictionary." + ib_push_warning(trx, error, + "Create or Alter table %s with foreign key constraint" + " failed. Foreign key constraint %s" + " already exists on data dictionary." " Foreign key constraint names need to be unique in database." " Error in foreign key definition: %s.", - buf, fk_def); + tablename, buf, fk_def); } return(error); @@ -1611,19 +1620,25 @@ dict_create_add_foreign_to_dictionary( if (error != DB_SUCCESS) { char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char tablename[MAX_TABLE_NAME_LEN + 1] = ""; char* field=NULL; char* field2=NULL; char* fk_def; + innobase_convert_name(tablename, MAX_TABLE_NAME_LEN, + table->name, strlen(table->name), + trx->mysql_thd, TRUE); innobase_convert_name(buf, MAX_TABLE_NAME_LEN, foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); fk_def = dict_foreign_def_get(foreign, trx); dict_foreign_def_get_fields(foreign, trx, &field, &field2, i); ib_push_warning(trx, error, - (const char *)"InnoDB: Error adding foreign key constraint name %s fields %s or %s to the dictionary." + "Create or Alter table %s with foreign key constraint" + " failed. Error adding foreign key constraint name %s" + " fields %s or %s to the dictionary." " Error in foreign key definition: %s.", - buf, i+1, fk_def); + tablename, buf, i+1, fk_def); return(error); } diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index cbb17fc5a6fae..4211d864d7cf5 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -2614,6 +2614,11 @@ dict_foreign_find( DBUG_RETURN(NULL); } +#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200 +#define DB_FOREIGN_KEY_COL_NOT_NULL 201 +#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202 +#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203 + /*********************************************************************//** Tries to find an index whose first fields are the columns in the array, in the same order and is not marked for deletion and is not the same @@ -2631,12 +2636,21 @@ dict_foreign_find_index( ibool check_charsets, /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must be declared NOT NULL */ + ulint* error, /*!< out: error code */ + ulint* err_col_no, + /*!< out: column number where error happened */ + dict_index_t** err_index) + /*!< out: index where error happened */ { dict_index_t* index; + if (error) { + *error = DB_FOREIGN_KEY_INDEX_NOT_FOUND; + } + index = dict_table_get_first_index(table); while (index != NULL) { @@ -2662,6 +2676,12 @@ dict_foreign_find_index( /* We do not accept column prefix indexes here */ + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_IS_PREFIX_INDEX; + *err_col_no = i; + *err_index = index; + } + break; } @@ -2673,6 +2693,11 @@ dict_foreign_find_index( if (check_null && (field->col->prtype & DATA_NOT_NULL)) { + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_COL_NOT_NULL; + *err_col_no = i; + *err_index = index; + } return(NULL); } @@ -2682,6 +2707,12 @@ dict_foreign_find_index( i), check_charsets)) { + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_COLS_NOT_EQUAL; + *err_col_no = i; + *err_index = index; + } + break; } } @@ -2689,6 +2720,10 @@ dict_foreign_find_index( if (i == n_cols) { /* We found a matching index */ + if (error) { + *error = DB_SUCCESS; + } + return(index); } } @@ -2720,7 +2755,7 @@ dict_foreign_find_equiv_index( foreign->foreign_table, foreign->foreign_col_names, foreign->n_fields, foreign->foreign_index, TRUE, /* check types */ - FALSE/* allow columns to be NULL */)); + FALSE/* allow columns to be NULL */, NULL, NULL, NULL)); } #endif /* !UNIV_HOTBACKUP */ @@ -2883,11 +2918,15 @@ dict_foreign_add_to_cache( } if (for_in_cache->referenced_table == NULL && ref_table) { + ulint index_error; + ulint err_col; + dict_index_t *err_index=NULL; + index = dict_foreign_find_index( ref_table, for_in_cache->referenced_col_names, for_in_cache->n_fields, for_in_cache->foreign_index, - check_charsets, FALSE); + check_charsets, FALSE, &index_error, &err_col, &err_index); if (index == NULL && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -2919,6 +2958,9 @@ dict_foreign_add_to_cache( } if (for_in_cache->foreign_table == NULL && for_table) { + ulint index_error; + ulint err_col; + dict_index_t* err_index=NULL; index = dict_foreign_find_index( for_table, @@ -2927,7 +2969,8 @@ dict_foreign_add_to_cache( for_in_cache->referenced_index, check_charsets, for_in_cache->type & (DICT_FOREIGN_ON_DELETE_SET_NULL - | DICT_FOREIGN_ON_UPDATE_SET_NULL)); + | DICT_FOREIGN_ON_UPDATE_SET_NULL), + &index_error, &err_col, &err_index); if (index == NULL && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -3538,6 +3581,8 @@ static void dict_foreign_report_syntax_err( /*===========================*/ + const char* fmt, /*!< in: syntax err msg */ + const char* oper, /*!< in: operation */ const char* name, /*!< in: table name */ const char* start_of_latest_foreign, /*!< in: start of the foreign key clause @@ -3548,11 +3593,101 @@ dict_foreign_report_syntax_err( mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nSyntax error close to:\n%s\n", - start_of_latest_foreign, ptr); + fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr); mutex_exit(&dict_foreign_err_mutex); } +/*********************************************************************//** +Push warning message to SQL-layer based on foreign key constraint +index match error. */ +static +void +dict_foreign_push_index_error( +/*==========================*/ + trx_t* trx, /*!< in: trx */ + const char* operation, /*!< in: operation create or alter + */ + const char* create_name, /*!< in: table name in create or + alter table */ + const char* latest_foreign, /*!< in: start of latest foreign key + constraint name */ + const char** columns, /*!< in: foreign key columns */ + ulint index_error, /*!< in: error code */ + ulint err_col, /*!< in: column where error happened + */ + dict_index_t* err_index, /*!< in: index where error happened + */ + dict_table_t* table, /*!< in: table */ + FILE* ef) /*!< in: output stream */ +{ + switch (index_error) { + case DB_FOREIGN_KEY_INDEX_NOT_FOUND: { + fprintf(ef, + "%s table '%s' with foreign key constraint" + " failed. There is no index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.\n", + operation, create_name, latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table '%s' with foreign key constraint" + " failed. There is no index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.", + operation, create_name, latest_foreign); + break; + } + case DB_FOREIGN_KEY_IS_PREFIX_INDEX: { + fprintf(ef, + "%s table '%s' with foreign key constraint" + " failed. There is only prefix index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.\n", + operation, create_name, latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table '%s' with foreign key constraint" + " failed. There is only prefix index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.", + operation, create_name, latest_foreign); + break; + } + case DB_FOREIGN_KEY_COL_NOT_NULL: { + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but " + "field %s on index is defined as NOT NULL close to %s\n", + operation, create_name, columns[err_col], latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but " + "field %s on index is defined as NOT NULL close to %s", + operation, create_name, columns[err_col], latest_foreign); + break; + } + case DB_FOREIGN_KEY_COLS_NOT_EQUAL: { + dict_field_t* field; + const char* col_name; + field = dict_index_get_nth_field(err_index, err_col); + + col_name = dict_table_get_col_name( + table, dict_col_get_no(field->col)); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Field type or character set for column %s " + "does not mach referenced column %s close to %s\n", + operation, create_name, columns[err_col], col_name, latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Field type or character set for column %s " + "does not mach referenced column %s close to %s", + operation, create_name, columns[err_col], col_name, latest_foreign); + break; + } + default: + ut_error; + } +} + /*********************************************************************//** 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 @@ -3581,15 +3716,20 @@ dict_create_foreign_constraints_low( DB_CANNOT_ADD_CONSTRAINT if any foreign keys are found. */ { - dict_table_t* table; - dict_table_t* referenced_table; - dict_table_t* table_to_alter; + dict_table_t* table = NULL; + dict_table_t* referenced_table = NULL; + dict_table_t* table_to_alter = NULL; + dict_table_t* table_to_create = NULL; ulint highest_id_so_far = 0; - dict_index_t* index; - dict_foreign_t* foreign; + dict_index_t* index = NULL; + dict_foreign_t* foreign = NULL; const char* ptr = sql_string; const char* start_of_latest_foreign = sql_string; + const char* start_of_latest_set = NULL; FILE* ef = dict_foreign_err_file; + ulint index_error = DB_SUCCESS; + dict_index_t* err_index = NULL; + ulint err_col; const char* constraint_name; ibool success; ulint error; @@ -3602,29 +3742,64 @@ dict_create_foreign_constraints_low( ulint n_on_updates; const dict_col_t*columns[500]; const char* column_names[500]; + const char* ref_column_names[500]; const char* referenced_table_name; + const char* create_table_name; + const char* orig; + const char create_name[MAX_TABLE_NAME_LEN + 1]; + const char operation[8]; ut_ad(mutex_own(&(dict_sys->mutex))); table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE); + /* First check if we are actually doing an ALTER TABLE, and in that + case look for the table being altered */ + ptr = dict_accept(cs, ptr, "ALTER", &success); + + strcpy((char *)operation, success ? "Alter " : "Create "); + + if (!success) { + orig = ptr; + ptr = dict_scan_to(ptr, "CREATE"); + ptr = dict_scan_to(ptr, "TABLE"); + ptr = dict_accept(cs, ptr, "TABLE", &success); + + if (success) { + ptr = dict_scan_table_name(cs, ptr, &table_to_create, name, + &success, heap, &create_table_name); + } + + if (success) { + innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + create_table_name, strlen(create_table_name), + trx->mysql_thd, TRUE); + ptr = orig; + } else { + ptr = orig; + innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + name, strlen(name), trx->mysql_thd, TRUE); + } + + goto loop; + } if (table == NULL) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, - "Cannot find the table in the internal" - " data dictionary of InnoDB.\n" - "Create table statement:\n%s\n", sql_string); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.\n", + operation, create_name, create_name, start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); - + ib_push_warning(trx, DB_ERROR, + "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.", + operation, create_name, create_name, start_of_latest_foreign); return(DB_ERROR); } - /* First check if we are actually doing an ALTER TABLE, and in that - case look for the table being altered */ - - ptr = dict_accept(cs, ptr, "ALTER", &success); - + /* If not alter table jump to loop */ if (!success) { goto loop; @@ -3639,13 +3814,35 @@ dict_create_foreign_constraints_low( /* We are doing an ALTER TABLE: scan the table name we are altering */ + orig = ptr; ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name, &success, heap, &referenced_table_name); + + if (table_to_alter) { + innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + table_to_alter->name, strlen(table_to_alter->name), + trx->mysql_thd, TRUE); + } else { + innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + } + if (!success) { - fprintf(stderr, - "InnoDB: Error: could not find" - " the table being ALTERED in:\n%s\n", - sql_string); + mutex_enter(&dict_foreign_err_mutex); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.\n", + operation, create_name, create_name, orig); + mutex_exit(&dict_foreign_err_mutex); + + ib_push_warning(trx, DB_ERROR, + "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.", + operation, create_name, create_name, orig); return(DB_ERROR); } @@ -3711,7 +3908,19 @@ dict_create_foreign_constraints_low( if so, immediately reject the command if the table is a temporary one. For now, this kludge will work. */ if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) { + mutex_enter(&dict_foreign_err_mutex); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, "%s table %s with foreign key constraint" + " failed. Temporary tables can't have foreign key constraints." + " Error close to %s.\n", + operation, create_name, start_of_latest_foreign); + mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Temporary tables can't have foreign key constraints." + " Error close to %s.", + operation, create_name, start_of_latest_foreign); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3747,11 +3956,21 @@ dict_create_foreign_constraints_low( if (!success) { /* MySQL allows also an index id before the '('; we skip it */ + orig = ptr; ptr = dict_skip_word(cs, ptr, &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3771,15 +3990,26 @@ dict_create_foreign_constraints_low( /* Scan the columns in the first list */ col_loop1: ut_a(i < (sizeof column_names) / sizeof *column_names); + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, table, columns + i, heap, column_names + i); if (!success) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3791,11 +4021,22 @@ dict_create_foreign_constraints_low( goto col_loop1; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3803,27 +4044,41 @@ dict_create_foreign_constraints_low( as the first fields and in the right order */ index = dict_foreign_find_index(table, column_names, i, - NULL, TRUE, FALSE); + NULL, TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); + dict_foreign_error_report_low(ef, create_name); fputs("There is no index in table ", ef); - ut_print_name(ef, NULL, TRUE, name); + ut_print_name(ef, NULL, TRUE, create_name); fprintf(ef, " where the columns appear\n" "as the first columns. Constraint:\n%s\n" "See " REFMAN "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", start_of_latest_foreign); - mutex_exit(&dict_foreign_err_mutex); - return(DB_CHILD_NO_INDEX); + dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign, + column_names, index_error, err_col, err_index, table, ef); + + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } + + orig = ptr; ptr = dict_accept(cs, ptr, "REFERENCES", &success); if (!success || !my_isspace(cs, *ptr)) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3872,24 +4127,48 @@ dict_create_foreign_constraints_low( checking of foreign key constraints! */ if (!success || (!referenced_table && trx->check_foreigns)) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " + "close to %s.", + operation, create_name, buf, start_of_latest_foreign); + dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve table name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " + "close to %s.\n", + operation, create_name, buf, start_of_latest_foreign); + mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); } + orig = ptr; ptr = dict_accept(cs, ptr, "(", &success); if (!success) { dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3897,20 +4176,29 @@ dict_create_foreign_constraints_low( i = 0; col_loop2: + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i, - heap, column_names + i); + heap, ref_column_names + i); i++; if (!success) { dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3920,13 +4208,23 @@ dict_create_foreign_constraints_low( goto col_loop2; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success || foreign->n_fields != i) { dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s. Too few referenced columns.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s. Too few referenced columns, you have %d when you should have %d.", + operation, create_name, start_of_latest_foreign, orig, i, foreign->n_fields); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3936,6 +4234,7 @@ dict_create_foreign_constraints_low( scan_on_conditions: /* Loop here as long as we can find ON ... conditions */ + start_of_latest_set = ptr; ptr = dict_accept(cs, ptr, "ON", &success); if (!success) { @@ -3946,13 +4245,24 @@ dict_create_foreign_constraints_low( ptr = dict_accept(cs, ptr, "DELETE", &success); if (!success) { + orig = ptr; ptr = dict_accept(cs, ptr, "UPDATE", &success); if (!success) { dict_foreign_free(foreign); dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3984,12 +4294,22 @@ dict_create_foreign_constraints_low( ptr = dict_accept(cs, ptr, "NO", &success); if (success) { + orig = ptr; ptr = dict_accept(cs, ptr, "ACTION", &success); if (!success) { dict_foreign_free(foreign); dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4003,42 +4323,73 @@ dict_create_foreign_constraints_low( goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "SET", &success); if (!success) { dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + return(DB_CANNOT_ADD_CONSTRAINT); } + orig = ptr; ptr = dict_accept(cs, ptr, "NULL", &success); if (!success) { dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); return(DB_CANNOT_ADD_CONSTRAINT); } for (j = 0; j < foreign->n_fields; j++) { if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype) & DATA_NOT_NULL) { + const dict_col_t* col + = dict_index_get_nth_col(foreign->foreign_index, j); + const char* col_name = dict_table_get_col_name(foreign->foreign_index->table, + dict_col_get_no(col)); /* It is not sensible to define SET NULL if the column is not allowed to be NULL! */ - dict_foreign_free(foreign); - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have defined a SET NULL condition" - " though some of the\n" - "columns are defined as NOT NULL.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL" + " in %s close to %s.\n", + operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set); mutex_exit(&dict_foreign_err_mutex); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL" + " in %s close to %s.", + operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set); + + dict_foreign_free(foreign); return(DB_CANNOT_ADD_CONSTRAINT); } } @@ -4055,16 +4406,22 @@ dict_create_foreign_constraints_low( if (n_on_deletes > 1 || n_on_updates > 1) { /* It is an error to define more than 1 action */ - dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have twice an ON DELETE clause" - " or twice an ON UPDATE clause.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have more than one on delete or on update clause" + " in %s close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. You have more than one on delete or on update clause" + " in %s close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + dict_foreign_free(foreign); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4074,13 +4431,13 @@ dict_create_foreign_constraints_low( if (referenced_table) { index = dict_foreign_find_index(referenced_table, - column_names, i, - foreign->foreign_index, - TRUE, FALSE); + ref_column_names, i, + foreign->foreign_index, + TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); + dict_foreign_error_report_low(ef, create_name); fprintf(ef, "%s:\n" "Cannot find an index in the" " referenced table where the\n" @@ -4098,9 +4455,13 @@ dict_create_foreign_constraints_low( "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", start_of_latest_foreign); + + dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign, + column_names, index_error, err_col, err_index, referenced_table, ef); + mutex_exit(&dict_foreign_err_mutex); - return(DB_PARENT_NO_INDEX); + return(DB_CANNOT_ADD_CONSTRAINT); } } else { ut_a(trx->check_foreigns == FALSE); @@ -4118,7 +4479,7 @@ dict_create_foreign_constraints_low( i * sizeof(void*)); for (i = 0; i < foreign->n_fields; i++) { foreign->referenced_col_names[i] - = mem_heap_strdup(foreign->heap, column_names[i]); + = mem_heap_strdup(foreign->heap, ref_column_names[i]); } /* We found an ok constraint definition: add to the lists */ @@ -5251,7 +5612,8 @@ dict_table_replace_index_in_foreign_list( foreign->referenced_table, foreign->referenced_col_names, foreign->n_fields, index, - /*check_charsets=*/TRUE, /*check_null=*/FALSE); + /*check_charsets=*/TRUE, /*check_null=*/FALSE, + NULL, NULL, NULL); ut_ad(new_index || !trx->check_foreigns); ut_ad(!new_index || new_index->table == index->table); diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h index 9faf580b0cc0e..a58bcb181aa8f 100644 --- a/storage/innobase/include/dict0crea.h +++ b/storage/innobase/include/dict0crea.h @@ -106,6 +106,17 @@ UNIV_INTERN ulint dict_create_or_check_foreign_constraint_tables(void); /*================================================*/ + +/********************************************************************//** +Construct foreign key constraint defintion from data dictionary information. +*/ +UNIV_INTERN +char* +dict_foreign_def_get( +/*=================*/ + dict_foreign_t* foreign,/*!< in: foreign */ + trx_t* trx); /*!< in: trx */ + /********************************************************************//** Adds foreign key definitions to data dictionary tables in the database. We look at table->foreign_list, and also generate names to constraints that were diff --git a/storage/xtradb/dict/dict0crea.c b/storage/xtradb/dict/dict0crea.c index 71a00ca8d0fc9..64a6d70655774 100644 --- a/storage/xtradb/dict/dict0crea.c +++ b/storage/xtradb/dict/dict0crea.c @@ -1629,9 +1629,10 @@ dict_create_add_foreign_field_to_dictionary( /********************************************************************//** Construct foreign key constraint defintion from data dictionary information. */ -static +UNIV_INTERN char* dict_foreign_def_get( +/*=================*/ dict_foreign_t* foreign,/*!< in: foreign */ trx_t* trx) /*!< in: trx */ { @@ -1691,6 +1692,7 @@ Convert foreign key column names from data dictionary to SQL-layer. static void dict_foreign_def_get_fields( +/*========================*/ dict_foreign_t* foreign,/*!< in: foreign */ trx_t* trx, /*!< in: trx */ char** field, /*!< out: foreign column */ @@ -1795,18 +1797,25 @@ dict_create_add_foreign_to_dictionary( if (error == DB_DUPLICATE_KEY) { char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char tablename[MAX_TABLE_NAME_LEN + 1] = ""; char* fk_def; + innobase_convert_name(tablename, MAX_TABLE_NAME_LEN, + table->name, strlen(table->name), + trx->mysql_thd, TRUE); + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); fk_def = dict_foreign_def_get(foreign, trx); - ib_push_warning(trx, error, (const char *)"InnoDB: foreign key constraint name %s " - "already exists on data dictionary." + ib_push_warning(trx, error, + "Create or Alter table %s with foreign key constraint" + " failed. Foreign key constraint %s" + " already exists on data dictionary." " Foreign key constraint names need to be unique in database." " Error in foreign key definition: %s.", - buf, fk_def); + tablename, buf, fk_def); } return(error); @@ -1818,19 +1827,25 @@ dict_create_add_foreign_to_dictionary( if (error != DB_SUCCESS) { char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char tablename[MAX_TABLE_NAME_LEN + 1] = ""; char* field=NULL; char* field2=NULL; char* fk_def; + innobase_convert_name(tablename, MAX_TABLE_NAME_LEN, + table->name, strlen(table->name), + trx->mysql_thd, TRUE); innobase_convert_name(buf, MAX_TABLE_NAME_LEN, foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); fk_def = dict_foreign_def_get(foreign, trx); dict_foreign_def_get_fields(foreign, trx, &field, &field2, i); ib_push_warning(trx, error, - (const char *)"InnoDB: Error adding foreign key constraint name %s fields %s or %s to the dictionary." + "Create or Alter table %s with foreign key constraint" + " failed. Error adding foreign key constraint name %s" + " fields %s or %s to the dictionary." " Error in foreign key definition: %s.", - buf, i+1, fk_def); + tablename, buf, i+1, fk_def); return(error); } diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c index bd0fdf6e9b904..754ddfa752d73 100644 --- a/storage/xtradb/dict/dict0dict.c +++ b/storage/xtradb/dict/dict0dict.c @@ -2747,6 +2747,11 @@ dict_foreign_find( DBUG_RETURN(NULL); } +#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200 +#define DB_FOREIGN_KEY_COL_NOT_NULL 201 +#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202 +#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203 + /*********************************************************************//** Tries to find an index whose first fields are the columns in the array, in the same order and is not marked for deletion and is not the same @@ -2764,12 +2769,21 @@ dict_foreign_find_index( ibool check_charsets, /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must be declared NOT NULL */ + ulint* error, /*!< out: error code */ + ulint* err_col_no, + /*!< out: column number where error happened */ + dict_index_t** err_index) + /*!< out: index where error happened */ { dict_index_t* index; + if (error) { + *error = DB_FOREIGN_KEY_INDEX_NOT_FOUND; + } + index = dict_table_get_first_index(table); while (index != NULL) { @@ -2795,6 +2809,12 @@ dict_foreign_find_index( /* We do not accept column prefix indexes here */ + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_IS_PREFIX_INDEX; + *err_col_no = i; + *err_index = index; + } + break; } @@ -2806,6 +2826,11 @@ dict_foreign_find_index( if (check_null && (field->col->prtype & DATA_NOT_NULL)) { + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_COL_NOT_NULL; + *err_col_no = i; + *err_index = index; + } return(NULL); } @@ -2815,6 +2840,12 @@ dict_foreign_find_index( i), check_charsets)) { + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_COLS_NOT_EQUAL; + *err_col_no = i; + *err_index = index; + } + break; } } @@ -2822,6 +2853,10 @@ dict_foreign_find_index( if (i == n_cols) { /* We found a matching index */ + if (error) { + *error = DB_SUCCESS; + } + return(index); } } @@ -2853,7 +2888,7 @@ dict_foreign_find_equiv_index( foreign->foreign_table, foreign->foreign_col_names, foreign->n_fields, foreign->foreign_index, TRUE, /* check types */ - FALSE/* allow columns to be NULL */)); + FALSE/* allow columns to be NULL */, NULL, NULL, NULL)); } #endif /* !UNIV_HOTBACKUP */ @@ -3016,11 +3051,15 @@ dict_foreign_add_to_cache( } if (for_in_cache->referenced_table == NULL && ref_table) { + ulint index_error; + ulint err_col; + dict_index_t *err_index=NULL; + index = dict_foreign_find_index( ref_table, for_in_cache->referenced_col_names, for_in_cache->n_fields, for_in_cache->foreign_index, - check_charsets, FALSE); + check_charsets, FALSE, &index_error, &err_col, &err_index); if (index == NULL && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -3052,6 +3091,9 @@ dict_foreign_add_to_cache( } if (for_in_cache->foreign_table == NULL && for_table) { + ulint index_error; + ulint err_col; + dict_index_t* err_index=NULL; index = dict_foreign_find_index( for_table, @@ -3060,7 +3102,8 @@ dict_foreign_add_to_cache( for_in_cache->referenced_index, check_charsets, for_in_cache->type & (DICT_FOREIGN_ON_DELETE_SET_NULL - | DICT_FOREIGN_ON_UPDATE_SET_NULL)); + | DICT_FOREIGN_ON_UPDATE_SET_NULL), + &index_error, &err_col, &err_index); if (index == NULL && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -3671,6 +3714,8 @@ static void dict_foreign_report_syntax_err( /*===========================*/ + const char* fmt, /*!< in: syntax err msg */ + const char* oper, /*!< in: operation */ const char* name, /*!< in: table name */ const char* start_of_latest_foreign, /*!< in: start of the foreign key clause @@ -3681,11 +3726,101 @@ dict_foreign_report_syntax_err( mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nSyntax error close to:\n%s\n", - start_of_latest_foreign, ptr); + fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr); mutex_exit(&dict_foreign_err_mutex); } +/*********************************************************************//** +Push warning message to SQL-layer based on foreign key constraint +index match error. */ +static +void +dict_foreign_push_index_error( +/*==========================*/ + trx_t* trx, /*!< in: trx */ + const char* operation, /*!< in: operation create or alter + */ + const char* create_name, /*!< in: table name in create or + alter table */ + const char* latest_foreign, /*!< in: start of latest foreign key + constraint name */ + const char** columns, /*!< in: foreign key columns */ + ulint index_error, /*!< in: error code */ + ulint err_col, /*!< in: column where error happened + */ + dict_index_t* err_index, /*!< in: index where error happened + */ + dict_table_t* table, /*!< in: table */ + FILE* ef) /*!< in: output stream */ +{ + switch (index_error) { + case DB_FOREIGN_KEY_INDEX_NOT_FOUND: { + fprintf(ef, + "%s table '%s' with foreign key constraint" + " failed. There is no index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.\n", + operation, create_name, latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table '%s' with foreign key constraint" + " failed. There is no index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.", + operation, create_name, latest_foreign); + break; + } + case DB_FOREIGN_KEY_IS_PREFIX_INDEX: { + fprintf(ef, + "%s table '%s' with foreign key constraint" + " failed. There is only prefix index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.\n", + operation, create_name, latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table '%s' with foreign key constraint" + " failed. There is only prefix index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.", + operation, create_name, latest_foreign); + break; + } + case DB_FOREIGN_KEY_COL_NOT_NULL: { + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but " + "field %s on index is defined as NOT NULL close to %s\n", + operation, create_name, columns[err_col], latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but " + "field %s on index is defined as NOT NULL close to %s", + operation, create_name, columns[err_col], latest_foreign); + break; + } + case DB_FOREIGN_KEY_COLS_NOT_EQUAL: { + dict_field_t* field; + const char* col_name; + field = dict_index_get_nth_field(err_index, err_col); + + col_name = dict_table_get_col_name( + table, dict_col_get_no(field->col)); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Field type or character set for column %s " + "does not mach referenced column %s close to %s\n", + operation, create_name, columns[err_col], col_name, latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Field type or character set for column %s " + "does not mach referenced column %s close to %s", + operation, create_name, columns[err_col], col_name, latest_foreign); + break; + } + default: + ut_error; + } +} + /*********************************************************************//** 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 @@ -3714,15 +3849,20 @@ dict_create_foreign_constraints_low( DB_CANNOT_ADD_CONSTRAINT if any foreign keys are found. */ { - dict_table_t* table; - dict_table_t* referenced_table; - dict_table_t* table_to_alter; + dict_table_t* table = NULL; + dict_table_t* referenced_table = NULL; + dict_table_t* table_to_alter = NULL; + dict_table_t* table_to_create = NULL; ulint highest_id_so_far = 0; - dict_index_t* index; - dict_foreign_t* foreign; + dict_index_t* index = NULL; + dict_foreign_t* foreign = NULL; const char* ptr = sql_string; const char* start_of_latest_foreign = sql_string; + const char* start_of_latest_set = NULL; FILE* ef = dict_foreign_err_file; + ulint index_error = DB_SUCCESS; + dict_index_t* err_index = NULL; + ulint err_col; const char* constraint_name; ibool success; ulint error; @@ -3735,29 +3875,64 @@ dict_create_foreign_constraints_low( ulint n_on_updates; const dict_col_t*columns[500]; const char* column_names[500]; + const char* ref_column_names[500]; const char* referenced_table_name; + const char* create_table_name; + const char* orig; + const char create_name[MAX_TABLE_NAME_LEN + 1]; + const char operation[8]; ut_ad(mutex_own(&(dict_sys->mutex))); table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE); + /* First check if we are actually doing an ALTER TABLE, and in that + case look for the table being altered */ + ptr = dict_accept(cs, ptr, "ALTER", &success); + + strcpy((char *)operation, success ? "Alter " : "Create "); + + if (!success) { + orig = ptr; + ptr = dict_scan_to(ptr, "CREATE"); + ptr = dict_scan_to(ptr, "TABLE"); + ptr = dict_accept(cs, ptr, "TABLE", &success); + + if (success) { + ptr = dict_scan_table_name(cs, ptr, &table_to_create, name, + &success, heap, &create_table_name); + } + + if (success) { + innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + create_table_name, strlen(create_table_name), + trx->mysql_thd, TRUE); + ptr = orig; + } else { + ptr = orig; + innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + name, strlen(name), trx->mysql_thd, TRUE); + } + + goto loop; + } if (table == NULL) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, - "Cannot find the table in the internal" - " data dictionary of InnoDB.\n" - "Create table statement:\n%s\n", sql_string); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.\n", + operation, create_name, create_name, start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); - + ib_push_warning(trx, DB_ERROR, + "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.", + operation, create_name, create_name, start_of_latest_foreign); return(DB_ERROR); } - /* First check if we are actually doing an ALTER TABLE, and in that - case look for the table being altered */ - - ptr = dict_accept(cs, ptr, "ALTER", &success); - + /* If not alter table jump to loop */ if (!success) { goto loop; @@ -3772,13 +3947,35 @@ dict_create_foreign_constraints_low( /* We are doing an ALTER TABLE: scan the table name we are altering */ + orig = ptr; ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name, &success, heap, &referenced_table_name); + + if (table_to_alter) { + innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + table_to_alter->name, strlen(table_to_alter->name), + trx->mysql_thd, TRUE); + } else { + innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + } + if (!success) { - fprintf(stderr, - "InnoDB: Error: could not find" - " the table being ALTERED in:\n%s\n", - sql_string); + mutex_enter(&dict_foreign_err_mutex); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.\n", + operation, create_name, create_name, orig); + mutex_exit(&dict_foreign_err_mutex); + + ib_push_warning(trx, DB_ERROR, + "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.", + operation, create_name, create_name, orig); return(DB_ERROR); } @@ -3844,7 +4041,19 @@ dict_create_foreign_constraints_low( if so, immediately reject the command if the table is a temporary one. For now, this kludge will work. */ if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) { + mutex_enter(&dict_foreign_err_mutex); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, "%s table %s with foreign key constraint" + " failed. Temporary tables can't have foreign key constraints." + " Error close to %s.\n", + operation, create_name, start_of_latest_foreign); + mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Temporary tables can't have foreign key constraints." + " Error close to %s.", + operation, create_name, start_of_latest_foreign); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3880,11 +4089,21 @@ dict_create_foreign_constraints_low( if (!success) { /* MySQL allows also an index id before the '('; we skip it */ + orig = ptr; ptr = dict_skip_word(cs, ptr, &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3904,15 +4123,26 @@ dict_create_foreign_constraints_low( /* Scan the columns in the first list */ col_loop1: ut_a(i < (sizeof column_names) / sizeof *column_names); + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, table, columns + i, heap, column_names + i); if (!success) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3924,11 +4154,22 @@ dict_create_foreign_constraints_low( goto col_loop1; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -3936,27 +4177,41 @@ dict_create_foreign_constraints_low( as the first fields and in the right order */ index = dict_foreign_find_index(table, column_names, i, - NULL, TRUE, FALSE); + NULL, TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); + dict_foreign_error_report_low(ef, create_name); fputs("There is no index in table ", ef); - ut_print_name(ef, NULL, TRUE, name); + ut_print_name(ef, NULL, TRUE, create_name); fprintf(ef, " where the columns appear\n" "as the first columns. Constraint:\n%s\n" "See " REFMAN "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", start_of_latest_foreign); - mutex_exit(&dict_foreign_err_mutex); - return(DB_CHILD_NO_INDEX); + dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign, + column_names, index_error, err_col, err_index, table, ef); + + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } + + orig = ptr; ptr = dict_accept(cs, ptr, "REFERENCES", &success); if (!success || !my_isspace(cs, *ptr)) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4005,24 +4260,48 @@ dict_create_foreign_constraints_low( checking of foreign key constraints! */ if (!success || (!referenced_table && trx->check_foreigns)) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " + "close to %s.", + operation, create_name, buf, start_of_latest_foreign); + dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve table name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " + "close to %s.\n", + operation, create_name, buf, start_of_latest_foreign); + mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); } + orig = ptr; ptr = dict_accept(cs, ptr, "(", &success); if (!success) { dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4030,20 +4309,29 @@ dict_create_foreign_constraints_low( i = 0; col_loop2: + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i, - heap, column_names + i); + heap, ref_column_names + i); i++; if (!success) { dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4053,13 +4341,23 @@ dict_create_foreign_constraints_low( goto col_loop2; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success || foreign->n_fields != i) { dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s. Too few referenced columns\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s. Too few referenced columns, you have %d when you should have %d.", + operation, create_name, start_of_latest_foreign, orig, i, foreign->n_fields); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4069,6 +4367,7 @@ dict_create_foreign_constraints_low( scan_on_conditions: /* Loop here as long as we can find ON ... conditions */ + start_of_latest_set = ptr; ptr = dict_accept(cs, ptr, "ON", &success); if (!success) { @@ -4079,13 +4378,24 @@ dict_create_foreign_constraints_low( ptr = dict_accept(cs, ptr, "DELETE", &success); if (!success) { + orig = ptr; ptr = dict_accept(cs, ptr, "UPDATE", &success); if (!success) { dict_foreign_free(foreign); dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4117,12 +4427,22 @@ dict_create_foreign_constraints_low( ptr = dict_accept(cs, ptr, "NO", &success); if (success) { + orig = ptr; ptr = dict_accept(cs, ptr, "ACTION", &success); if (!success) { dict_foreign_free(foreign); dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4136,42 +4456,73 @@ dict_create_foreign_constraints_low( goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "SET", &success); if (!success) { dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + return(DB_CANNOT_ADD_CONSTRAINT); } + orig = ptr; ptr = dict_accept(cs, ptr, "NULL", &success); if (!success) { dict_foreign_free(foreign); - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); return(DB_CANNOT_ADD_CONSTRAINT); } for (j = 0; j < foreign->n_fields; j++) { if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype) & DATA_NOT_NULL) { + const dict_col_t* col + = dict_index_get_nth_col(foreign->foreign_index, j); + const char* col_name = dict_table_get_col_name(foreign->foreign_index->table, + dict_col_get_no(col)); /* It is not sensible to define SET NULL if the column is not allowed to be NULL! */ - dict_foreign_free(foreign); - mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have defined a SET NULL condition" - " though some of the\n" - "columns are defined as NOT NULL.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL" + " in %s close to %s.\n", + operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set); mutex_exit(&dict_foreign_err_mutex); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL" + " in %s close to %s.", + operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set); + + dict_foreign_free(foreign); return(DB_CANNOT_ADD_CONSTRAINT); } } @@ -4188,16 +4539,22 @@ dict_create_foreign_constraints_low( if (n_on_deletes > 1 || n_on_updates > 1) { /* It is an error to define more than 1 action */ - dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have twice an ON DELETE clause" - " or twice an ON UPDATE clause.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have more than one on delete or on update clause" + " in %s close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. You have more than one on delete or on update clause" + " in %s close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + dict_foreign_free(foreign); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4207,13 +4564,13 @@ dict_create_foreign_constraints_low( if (referenced_table) { index = dict_foreign_find_index(referenced_table, - column_names, i, - foreign->foreign_index, - TRUE, FALSE); + ref_column_names, i, + foreign->foreign_index, + TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); + dict_foreign_error_report_low(ef, create_name); fprintf(ef, "%s:\n" "Cannot find an index in the" " referenced table where the\n" @@ -4231,9 +4588,13 @@ dict_create_foreign_constraints_low( "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", start_of_latest_foreign); + + dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign, + column_names, index_error, err_col, err_index, referenced_table, ef); + mutex_exit(&dict_foreign_err_mutex); - return(DB_PARENT_NO_INDEX); + return(DB_CANNOT_ADD_CONSTRAINT); } } else { ut_a(trx->check_foreigns == FALSE); @@ -4251,7 +4612,7 @@ dict_create_foreign_constraints_low( i * sizeof(void*)); for (i = 0; i < foreign->n_fields; i++) { foreign->referenced_col_names[i] - = mem_heap_strdup(foreign->heap, column_names[i]); + = mem_heap_strdup(foreign->heap, ref_column_names[i]); } /* We found an ok constraint definition: add to the lists */ @@ -5796,7 +6157,8 @@ dict_table_replace_index_in_foreign_list( foreign->referenced_table, foreign->referenced_col_names, foreign->n_fields, index, - /*check_charsets=*/TRUE, /*check_null=*/FALSE); + /*check_charsets=*/TRUE, /*check_null=*/FALSE, + NULL, NULL, NULL); ut_ad(new_index || !trx->check_foreigns); ut_ad(!new_index || new_index->table == index->table); diff --git a/storage/xtradb/include/dict0crea.h b/storage/xtradb/include/dict0crea.h index 762ab54a35309..c67910f0d5509 100644 --- a/storage/xtradb/include/dict0crea.h +++ b/storage/xtradb/include/dict0crea.h @@ -121,6 +121,17 @@ UNIV_INTERN ulint dict_create_or_check_foreign_constraint_tables(void); /*================================================*/ + +/********************************************************************//** +Construct foreign key constraint defintion from data dictionary information. +*/ +UNIV_INTERN +char* +dict_foreign_def_get( +/*=================*/ + dict_foreign_t* foreign,/*!< in: foreign */ + trx_t* trx); /*!< in: trx */ + /********************************************************************//** Adds foreign key definitions to data dictionary tables in the database. We look at table->foreign_list, and also generate names to constraints that were From 1ad294e06430d9fa2dd7e4dd84ffd7909aff0ca5 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 30 Jul 2015 18:51:44 +0400 Subject: [PATCH 37/47] MDEV-7821 - Server crashes in Item_func_group_concat::fix_fields on 2nd execution of PS GROUP_CONCAT() with ORDER BY column position may crash server on PS reexecution. The problem was that arguments array of GROUP_CONCAT() was adjusted to point to temporary elements (resolved ORDER BY fields) during first execution. This patch expands rev. 08763096cb to restore original arguments array as well. --- mysql-test/r/func_gconcat.result | 16 ++++++++++++++++ mysql-test/t/func_gconcat.test | 11 +++++++++++ sql/item_sum.cc | 3 +++ 3 files changed, 30 insertions(+) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index f12a0c1127a17..0bc31a5e85b2a 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -1103,3 +1103,19 @@ ORDER BY field; field c,c drop table t3, t2, t1; +# +# MDEV-7821 - Server crashes in Item_func_group_concat::fix_fields on 2nd +# execution of PS +# +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(1),(2); +PREPARE stmt FROM "SELECT GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0) FROM t1 AS t1a, t1 AS t1b GROUP BY t1a.a"; +EXECUTE stmt; +GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0) +1,1 +2,2 +EXECUTE stmt; +GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0) +1,1 +2,2 +DROP TABLE t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 42a30760a863a..5550eebf1a393 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -821,3 +821,14 @@ FROM ( SELECT * FROM t2 ) AS sq2, t3 ORDER BY field; drop table t3, t2, t1; + +--echo # +--echo # MDEV-7821 - Server crashes in Item_func_group_concat::fix_fields on 2nd +--echo # execution of PS +--echo # +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES(1),(2); +PREPARE stmt FROM "SELECT GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0) FROM t1 AS t1a, t1 AS t1b GROUP BY t1a.a"; +EXECUTE stmt; +EXECUTE stmt; +DROP TABLE t1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index d8970ca26b5d4..a24307b131bf0 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3300,6 +3300,8 @@ void Item_func_group_concat::cleanup() from Item_func_group_concat::setup() to point to runtime created objects, we need to reset them back to the original arguments of the function. + + The very same applies to args array. */ ORDER **order_ptr= order; for (uint i= 0; i < arg_count_order; i++) @@ -3307,6 +3309,7 @@ void Item_func_group_concat::cleanup() (*order_ptr)->item= &args[arg_count_field + i]; order_ptr++; } + memcpy(args, orig_args, sizeof(Item *) * arg_count); DBUG_VOID_RETURN; } From 360e597c3c9f6adbe113f80d3d9cd9afc3b81f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 31 Jul 2015 12:06:29 +0300 Subject: [PATCH 38/47] Make sure name buffer has string end marker on correct place. --- storage/innobase/dict/dict0crea.c | 47 +++++++++++++++++++------------ storage/innobase/dict/dict0dict.c | 41 +++++++++++++++++---------- storage/xtradb/dict/dict0crea.c | 47 +++++++++++++++++++------------ storage/xtradb/dict/dict0dict.c | 41 +++++++++++++++++---------- 4 files changed, 110 insertions(+), 66 deletions(-) diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 87fbd4626976f..dcbca492b0848 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -1433,10 +1433,12 @@ dict_foreign_def_get( const char* tbname; char tablebuf[MAX_TABLE_NAME_LEN + 1] = ""; int i; + char* bufend; tbname = dict_remove_db_name(foreign->id); - innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, tbname, strlen(tbname), trx->mysql_thd, FALSE); + tablebuf[bufend - tablebuf] = '\0'; sprintf(fk_def, (char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf); @@ -1455,20 +1457,22 @@ dict_foreign_def_get( strcat(fk_def,(char *)") REFERENCES "); - innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, - foreign->referenced_table_name, - strlen(foreign->referenced_table_name), - trx->mysql_thd, TRUE); + bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + foreign->referenced_table_name, + strlen(foreign->referenced_table_name), + trx->mysql_thd, TRUE); + tablebuf[bufend - tablebuf] = '\0'; strcat(fk_def, tablebuf); strcat(fk_def, " ("); for(i = 0; i < foreign->n_fields; i++) { char buf[MAX_TABLE_NAME_LEN + 1] = ""; - innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN, foreign->referenced_col_names[i], strlen(foreign->referenced_col_names[i]), trx->mysql_thd, FALSE); + buf[bufend - buf] = '\0'; strcat(fk_def, buf); if (i < foreign->n_fields-1) { strcat(fk_def, (char *)","); @@ -1492,18 +1496,25 @@ dict_foreign_def_get_fields( char** field2, /*!< out: referenced column */ int col_no) /*!< in: column number */ { - *field = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); - *field2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); - - innobase_convert_name(*field, MAX_TABLE_NAME_LEN, - foreign->foreign_col_names[col_no], - strlen(foreign->foreign_col_names[col_no]), - trx->mysql_thd, FALSE); - - innobase_convert_name(*field, MAX_TABLE_NAME_LEN, - foreign->referenced_col_names[col_no], - strlen(foreign->referenced_col_names[col_no]), - trx->mysql_thd, FALSE); + char* bufend; + char* fieldbuf = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + char* fieldbuf2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + + bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN, + foreign->foreign_col_names[col_no], + strlen(foreign->foreign_col_names[col_no]), + trx->mysql_thd, FALSE); + + fieldbuf[bufend - fieldbuf] = '\0'; + + bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN, + foreign->referenced_col_names[col_no], + strlen(foreign->referenced_col_names[col_no]), + trx->mysql_thd, FALSE); + + fieldbuf2[bufend - fieldbuf2] = '\0'; + *field = fieldbuf; + *field2 = fieldbuf2; } /********************************************************************//** diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 4211d864d7cf5..c803169dbd76e 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -3746,7 +3746,7 @@ dict_create_foreign_constraints_low( const char* referenced_table_name; const char* create_table_name; const char* orig; - const char create_name[MAX_TABLE_NAME_LEN + 1]; + char create_name[MAX_TABLE_NAME_LEN + 1]; const char operation[8]; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -3770,14 +3770,18 @@ dict_create_foreign_constraints_low( } if (success) { - innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, - create_table_name, strlen(create_table_name), - trx->mysql_thd, TRUE); + char *bufend; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + create_table_name, strlen(create_table_name), + trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; ptr = orig; } else { + char *bufend; ptr = orig; - innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, - name, strlen(name), trx->mysql_thd, TRUE); + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + name, strlen(name), trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; } goto loop; @@ -3819,13 +3823,18 @@ dict_create_foreign_constraints_low( &success, heap, &referenced_table_name); if (table_to_alter) { - innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, - table_to_alter->name, strlen(table_to_alter->name), - trx->mysql_thd, TRUE); + char *bufend; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + table_to_alter->name, strlen(table_to_alter->name), + trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; } else { - innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, - referenced_table_name, strlen(referenced_table_name), - trx->mysql_thd, TRUE); + char *bufend; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; + } if (!success) { @@ -4128,10 +4137,12 @@ dict_create_foreign_constraints_low( if (!success || (!referenced_table && trx->check_foreigns)) { char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char* bufend; - innobase_convert_name(buf, MAX_TABLE_NAME_LEN, - referenced_table_name, strlen(referenced_table_name), - trx->mysql_thd, TRUE); + bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + buf[bufend - buf] = '\0'; ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " diff --git a/storage/xtradb/dict/dict0crea.c b/storage/xtradb/dict/dict0crea.c index 64a6d70655774..f7663b999b74c 100644 --- a/storage/xtradb/dict/dict0crea.c +++ b/storage/xtradb/dict/dict0crea.c @@ -1640,10 +1640,12 @@ dict_foreign_def_get( const char* tbname; char tablebuf[MAX_TABLE_NAME_LEN + 1] = ""; int i; + char* bufend; tbname = dict_remove_db_name(foreign->id); - innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, tbname, strlen(tbname), trx->mysql_thd, FALSE); + tablebuf[bufend - tablebuf] = '\0'; sprintf(fk_def, (char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf); @@ -1662,20 +1664,22 @@ dict_foreign_def_get( strcat(fk_def,(char *)") REFERENCES "); - innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, - foreign->referenced_table_name, - strlen(foreign->referenced_table_name), - trx->mysql_thd, TRUE); + bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + foreign->referenced_table_name, + strlen(foreign->referenced_table_name), + trx->mysql_thd, TRUE); + tablebuf[bufend - tablebuf] = '\0'; strcat(fk_def, tablebuf); strcat(fk_def, " ("); for(i = 0; i < foreign->n_fields; i++) { char buf[MAX_TABLE_NAME_LEN + 1] = ""; - innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN, foreign->referenced_col_names[i], strlen(foreign->referenced_col_names[i]), trx->mysql_thd, FALSE); + buf[bufend - buf] = '\0'; strcat(fk_def, buf); if (i < foreign->n_fields-1) { strcat(fk_def, (char *)","); @@ -1699,18 +1703,25 @@ dict_foreign_def_get_fields( char** field2, /*!< out: referenced column */ int col_no) /*!< in: column number */ { - *field = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); - *field2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); - - innobase_convert_name(*field, MAX_TABLE_NAME_LEN, - foreign->foreign_col_names[col_no], - strlen(foreign->foreign_col_names[col_no]), - trx->mysql_thd, FALSE); - - innobase_convert_name(*field, MAX_TABLE_NAME_LEN, - foreign->referenced_col_names[col_no], - strlen(foreign->referenced_col_names[col_no]), - trx->mysql_thd, FALSE); + char* bufend; + char* fieldbuf = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + char* fieldbuf2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + + bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN, + foreign->foreign_col_names[col_no], + strlen(foreign->foreign_col_names[col_no]), + trx->mysql_thd, FALSE); + + fieldbuf[bufend - fieldbuf] = '\0'; + + bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN, + foreign->referenced_col_names[col_no], + strlen(foreign->referenced_col_names[col_no]), + trx->mysql_thd, FALSE); + + fieldbuf2[bufend - fieldbuf2] = '\0'; + *field = fieldbuf; + *field2 = fieldbuf2; } /********************************************************************//** diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c index 754ddfa752d73..d18184f6e30d5 100644 --- a/storage/xtradb/dict/dict0dict.c +++ b/storage/xtradb/dict/dict0dict.c @@ -3879,7 +3879,7 @@ dict_create_foreign_constraints_low( const char* referenced_table_name; const char* create_table_name; const char* orig; - const char create_name[MAX_TABLE_NAME_LEN + 1]; + char create_name[MAX_TABLE_NAME_LEN + 1]; const char operation[8]; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -3903,14 +3903,18 @@ dict_create_foreign_constraints_low( } if (success) { - innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, - create_table_name, strlen(create_table_name), - trx->mysql_thd, TRUE); + char *bufend; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + create_table_name, strlen(create_table_name), + trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; ptr = orig; } else { + char *bufend; ptr = orig; - innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, - name, strlen(name), trx->mysql_thd, TRUE); + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + name, strlen(name), trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; } goto loop; @@ -3952,13 +3956,18 @@ dict_create_foreign_constraints_low( &success, heap, &referenced_table_name); if (table_to_alter) { - innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, - table_to_alter->name, strlen(table_to_alter->name), - trx->mysql_thd, TRUE); + char *bufend; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + table_to_alter->name, strlen(table_to_alter->name), + trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; } else { - innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, - referenced_table_name, strlen(referenced_table_name), - trx->mysql_thd, TRUE); + char *bufend; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; + } if (!success) { @@ -4261,10 +4270,12 @@ dict_create_foreign_constraints_low( if (!success || (!referenced_table && trx->check_foreigns)) { char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char* bufend; - innobase_convert_name(buf, MAX_TABLE_NAME_LEN, - referenced_table_name, strlen(referenced_table_name), - trx->mysql_thd, TRUE); + bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + buf[bufend - buf] = '\0'; ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " From bfe2689cf642aac122c8cf8493863dff38f69558 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Fri, 31 Jul 2015 13:13:39 +0400 Subject: [PATCH 39/47] MDEV-8379 - SUSE mariadb patches Let mysql_upgrade return zero exit status when installation is up to date. --- client/mysql_upgrade.c | 3 ++- mysql-test/t/mysql_upgrade.test | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index d513d5d852d35..ee6845def6807 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1061,7 +1061,7 @@ int main(int argc, char **argv) printf("This installation of MySQL is already upgraded to %s, " "use --force if you still need to run mysql_upgrade\n", MYSQL_SERVER_VERSION); - die(NULL); + goto end; } if (opt_version_check && check_version_match()) @@ -1084,6 +1084,7 @@ int main(int argc, char **argv) /* Create a file indicating upgrade has been performed */ create_mysql_upgrade_info_file(); +end: free_used_memory(); my_end(my_end_arg); exit(0); diff --git a/mysql-test/t/mysql_upgrade.test b/mysql-test/t/mysql_upgrade.test index e4923e5f429a7..13be03aa9bba0 100644 --- a/mysql-test/t/mysql_upgrade.test +++ b/mysql-test/t/mysql_upgrade.test @@ -14,7 +14,6 @@ file_exists $MYSQLD_DATADIR/mysql_upgrade_info; --echo Run it again - should say already completed --replace_result $MYSQL_SERVER_VERSION VERSION ---error 1 --exec $MYSQL_UPGRADE 2>&1 # It should have created a file in the MySQL Servers datadir From 2721d69f792353e509056819565202483003ab3d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 28 Jul 2015 19:11:53 +0200 Subject: [PATCH 40/47] MDEV-8352 Increase Diffie-Helman modulus to 2048-bits --- vio/viosslfactories.c | 47 ++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 78916f843e0d4..c889b90a2e25f 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -21,31 +21,42 @@ static my_bool ssl_algorithms_added = FALSE; static my_bool ssl_error_strings_loaded= FALSE; -/* the function below was generated with "openssl dhparam -2 -C 1024" */ +/* the function below was generated with "openssl dhparam -2 -C 2048" */ static -DH *get_dh1024() +DH *get_dh2048() { - static unsigned char dh1024_p[]={ - 0xEC,0x46,0x7E,0xF9,0x4E,0x10,0x29,0xDC,0x44,0x97,0x71,0xFD, - 0x71,0xC6,0x9F,0x0D,0xD1,0x09,0xF6,0x58,0x6F,0xAD,0xCA,0xF4, - 0x37,0xD5,0xC3,0xBD,0xC3,0x9A,0x51,0x66,0x2C,0x58,0xBD,0x02, - 0xBD,0xBA,0xBA,0xFC,0xE7,0x0E,0x5A,0xE5,0x97,0x81,0xC3,0xF3, - 0x28,0x2D,0xAD,0x00,0x91,0xEF,0xF8,0xF0,0x5D,0xE9,0xE7,0x18, - 0xE2,0xAD,0xC4,0x70,0xC5,0x3C,0x12,0x8A,0x80,0x6A,0x9F,0x3B, - 0x00,0xA2,0x8F,0xA9,0x26,0xB0,0x0E,0x7F,0xED,0xF6,0xC2,0x03, - 0x81,0xB5,0xC5,0x41,0xD0,0x00,0x2B,0x21,0xD4,0x4B,0x74,0xA6, - 0xD7,0x1A,0x0E,0x82,0xC8,0xEE,0xD4,0xB1,0x6F,0xB4,0x79,0x01, - 0x8A,0xF1,0x12,0xD7,0x3C,0xFD,0xCB,0x9B,0xAE,0x1C,0xA9,0x0F, - 0x3D,0x0F,0xF8,0xD6,0x7D,0xDE,0xD6,0x0B, + static unsigned char dh2048_p[]={ + 0xA1,0xBB,0x7C,0x20,0xC5,0x5B,0xC0,0x7B,0x21,0x8B,0xD6,0xA8, + 0x15,0xFC,0x3B,0xBA,0xAB,0x9F,0xDF,0x68,0xC4,0x79,0x78,0x0D, + 0xC1,0x12,0x64,0xE4,0x15,0xC9,0x66,0xDB,0xF6,0xCB,0xB3,0x39, + 0x02,0x5B,0x78,0x62,0xFB,0x09,0xAE,0x09,0x6B,0xDD,0xD4,0x5D, + 0x97,0xBC,0xDC,0x7F,0xE6,0xD6,0xF1,0xCB,0xF5,0xEB,0xDA,0xA7, + 0x2E,0x5A,0x43,0x2B,0xE9,0x40,0xE2,0x85,0x00,0x1C,0xC0,0x0A, + 0x98,0x77,0xA9,0x31,0xDE,0x0B,0x75,0x4D,0x1E,0x1F,0x16,0x83, + 0xCA,0xDE,0xBD,0x21,0xFC,0xC1,0x82,0x37,0x36,0x33,0x0B,0x66, + 0x06,0x3C,0xF3,0xAF,0x21,0x57,0x57,0x80,0xF6,0x94,0x1B,0xA9, + 0xD4,0xF6,0x8F,0x18,0x62,0x0E,0xC4,0x22,0xF9,0x5B,0x62,0xCC, + 0x3F,0x19,0x95,0xCF,0x4B,0x00,0xA6,0x6C,0x0B,0xAF,0x9F,0xD5, + 0xFA,0x3D,0x6D,0xDA,0x30,0x83,0x07,0x91,0xAC,0x15,0xFF,0x8F, + 0x59,0x54,0xEA,0x25,0xBC,0x4E,0xEB,0x6A,0x54,0xDF,0x75,0x09, + 0x72,0x0F,0xEF,0x23,0x70,0xE0,0xA8,0x04,0xEA,0xFF,0x90,0x54, + 0xCD,0x84,0x18,0xC0,0x75,0x91,0x99,0x0F,0xA1,0x78,0x0C,0x07, + 0xB7,0xC5,0xDE,0x55,0x06,0x7B,0x95,0x68,0x2C,0x33,0x39,0xBC, + 0x2C,0xD0,0x6D,0xDD,0xFA,0xDC,0xB5,0x8F,0x82,0x39,0xF8,0x67, + 0x44,0xF1,0xD8,0xF7,0x78,0x11,0x9A,0x77,0x9B,0x53,0x47,0xD6, + 0x2B,0x5D,0x67,0xB8,0xB7,0xBC,0xC1,0xD7,0x79,0x62,0x15,0xC2, + 0xC5,0x83,0x97,0xA7,0xF8,0xB4,0x9C,0xF6,0x8F,0x9A,0xC7,0xDA, + 0x1B,0xBB,0x87,0x07,0xA7,0x71,0xAD,0xB2,0x8A,0x50,0xF8,0x26, + 0x12,0xB7,0x3E,0x0B, }; - static unsigned char dh1024_g[]={ + static unsigned char dh2048_g[]={ 0x02, }; DH *dh; if ((dh=DH_new()) == NULL) return(NULL); - dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL); - dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL); + dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL); + dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL); if ((dh->p == NULL) || (dh->g == NULL)) { DH_free(dh); return(NULL); } return(dh); @@ -259,7 +270,7 @@ new_VioSSLFd(const char *key_file, const char *cert_file, } /* DH stuff */ - dh=get_dh1024(); + dh=get_dh2048(); SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh); DH_free(dh); From 4d5772c578bd336b1004084ad7925143137c8a4e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 31 Jul 2015 10:13:01 +0200 Subject: [PATCH 41/47] MDEV-7810 Wrong result on execution of a query as a PS (both 1st and further executions) Alternative fix that doesn't cause view.test crash in --ps: Remember when Item_ref was fixed right in the constructor and did not have a full Item_ref::fix_fields() call. Later in PS/SP, after Item_ref::cleanup, we use this knowledge to avoid doing full fix_fields() for items that were never supposed to be fix_field'ed. Simplify the test case. --- mysql-test/r/subselect_mat.result | 13 ++---------- mysql-test/r/subselect_sj_mat.result | 13 ++---------- mysql-test/t/subselect_sj_mat.test | 8 ++----- sql/item.cc | 10 ++++++--- sql/item.h | 5 +++-- sql/item_subselect.cc | 31 ---------------------------- sql/sql_base.cc | 2 ++ 7 files changed, 18 insertions(+), 64 deletions(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 8c25577eb019d..e4843929fcb00 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -2150,20 +2150,11 @@ drop database mysqltest4; # (both 1st and further executions) CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM; INSERT INTO t1 VALUES (0),(8); -SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2; -a -0 -8 -SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a)); -MIN(t3.a) -0 -SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq -WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ); +SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2)); a 0 PREPARE stmt FROM " -SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq -WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ) +SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2)) "; execute stmt; a diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 6c69d195bd33b..cfcbf612030e5 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -2190,20 +2190,11 @@ drop database mysqltest4; # (both 1st and further executions) CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM; INSERT INTO t1 VALUES (0),(8); -SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2; -a -0 -8 -SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a)); -MIN(t3.a) -0 -SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq -WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ); +SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2)); a 0 PREPARE stmt FROM " -SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq -WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ) +SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2)) "; execute stmt; a diff --git a/mysql-test/t/subselect_sj_mat.test b/mysql-test/t/subselect_sj_mat.test index 63c72f20e2135..dd30b21201d96 100644 --- a/mysql-test/t/subselect_sj_mat.test +++ b/mysql-test/t/subselect_sj_mat.test @@ -1848,13 +1848,9 @@ drop database mysqltest4; CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM; INSERT INTO t1 VALUES (0),(8); -SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2; -SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a)); -SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq -WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ); +SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2)); PREPARE stmt FROM " -SELECT a FROM ( SELECT DISTINCT t9.* FROM t1 AS t9, t1 AS t2 ) AS sq -WHERE a IN ( SELECT MIN(t3.a) FROM ( t1 AS t3 INNER JOIN t1 AS t4 ON (t3.a = t4.a) ) ) +SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2)) "; execute stmt; execute stmt; diff --git a/sql/item.cc b/sql/item.cc index 9b3e9a546c6bf..878c9604ca27f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6754,7 +6754,7 @@ Item_ref::Item_ref(Name_resolution_context *context_arg, /* This constructor used to create some internals references over fixed items */ - if (ref && *ref && (*ref)->fixed) + if ((set_properties_only= (ref && *ref && (*ref)->fixed))) set_properties(); } @@ -6798,7 +6798,7 @@ Item_ref::Item_ref(TABLE_LIST *view_arg, Item **item, /* This constructor is used to create some internal references over fixed items */ - if (ref && *ref && (*ref)->fixed) + if ((set_properties_only= (ref && *ref && (*ref)->fixed))) set_properties(); } @@ -6873,7 +6873,11 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) DBUG_ASSERT(fixed == 0); SELECT_LEX *current_sel= thd->lex->current_select; - if (!ref || ref == not_found_item) + if (set_properties_only) + { + /* do nothing */ + } + else if (!ref || ref == not_found_item) { DBUG_ASSERT(reference_trough_name != 0); if (!(ref= resolve_ref_in_select_and_group(thd, this, diff --git a/sql/item.h b/sql/item.h index a38a25dfc7578..f8e8ead47dd64 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2946,6 +2946,7 @@ class Item_ref :public Item_ident { protected: void set_properties(); + bool set_properties_only; // the item doesn't need full fix_fields public: enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF, AGGREGATE_REF }; Field *result_field; /* Save result here */ @@ -2955,7 +2956,7 @@ class Item_ref :public Item_ident const char *db_arg, const char *table_name_arg, const char *field_name_arg) :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg), - result_field(0), ref(0), reference_trough_name(1) {} + set_properties_only(0), result_field(0), ref(0), reference_trough_name(1) {} /* This constructor is used in two scenarios: A) *item = NULL @@ -2978,7 +2979,7 @@ class Item_ref :public Item_ident /* Constructor need to process subselect with temporary tables (see Item) */ Item_ref(THD *thd, Item_ref *item) - :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} + :Item_ident(thd, item), set_properties_only(0), result_field(item->result_field), ref(item->ref) {} enum Type type() const { return REF_ITEM; } enum Type real_type() const { return ref ? (*ref)->type() : REF_ITEM; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 3b280c4560811..4837cb45a91d1 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2007,37 +2007,6 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join, *where_item= NULL; *having_item= NULL; - /* - For PS we have to do fix_fields(expr) here to ensure that it's - evaluated in the outer context. If not, then fix_having() will do - a fix_fields(expr) in the inner context and mark expr as - 'depended', which will cause update_ref_and_keys() to find wrong - keys. - When not running PS, fix_fields(expr) as already been done earlier and - the following test does nothing. - */ - if (expr && !expr->fixed) - { - bool tmp; - SELECT_LEX *save_current_select= thd->lex->current_select; - Item_subselect *save_item; - - thd->lex->current_select= thd->lex->current_select->outer_select(); - /* - For st_select_lex::mark_as_dependent, who needs to mark - this sub query as correlated. - */ - save_item= thd->lex->current_select->master_unit()->item; - thd->lex->current_select->master_unit()->item= this; - - tmp= expr->fix_fields(thd, 0); - - thd->lex->current_select->master_unit()->item= save_item; - thd->lex->current_select= save_current_select; - if (tmp) - DBUG_RETURN(true); - } - if (join_having || select_lex->with_sum_func || select_lex->group_list.elements) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index aefa82405ff78..384ab7a73223b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6936,6 +6936,8 @@ find_field_in_tables(THD *thd, Item_ident *item, return found; } } + else + item->can_be_depended= TRUE; if (db && lower_case_table_names) { From 79deefc4d798f912580ab10786a46d262bc21f28 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 31 Jul 2015 12:31:37 +0200 Subject: [PATCH 42/47] MDEV-8340 Add "mysqlbinlog --binlog-row-event-max-size" support for MariaDB 5.5 Cherry-pick from 10.0: commit 126523d1906727254ad0f887db688b60b23ebed6 Author: Sergei Golubchik Date: Mon Feb 23 20:53:41 2015 +0100 MDEV-6703 Add "mysqlbinlog --binlog-row-event-max-size" support --- client/mysqlbinlog.cc | 7 +++++++ sql/log_event.cc | 12 +++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 57492577e9182..250dc6098917f 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -66,6 +66,7 @@ ulong server_id = 0; ulong bytes_sent = 0L, bytes_received = 0L; ulong mysqld_net_retry_count = 10L; ulong open_files_limit; +ulong opt_binlog_rows_event_max_size; uint test_flags = 0; static uint opt_protocol= 0; static FILE *result_file; @@ -1432,6 +1433,12 @@ that may lead to an endless loop.", "Used to reserve file descriptors for use by this program.", &open_files_limit, &open_files_limit, 0, GET_ULONG, REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, + {"binlog-row-event-max-size", 0, + "The maximum size of a row-based binary log event in bytes. Rows will be " + "grouped into events smaller than this size if possible. " + "This value must be a multiple of 256.", + &opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size, 0, + GET_ULONG, REQUIRED_ARG, UINT_MAX, 256, ULONG_MAX, 0, 256, 0}, {"verify-binlog-checksum", 'c', "Verify checksum binlog events.", (uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/sql/log_event.cc b/sql/log_event.cc index e63884eaeab01..2d5c3f232a4ef 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1249,9 +1249,10 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet, } data_len= uint4korr(buf + EVENT_LEN_OFFSET); if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN || - data_len > current_thd->variables.max_allowed_packet) + data_len > max(current_thd->variables.max_allowed_packet, + opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER)) { - DBUG_PRINT("error",("data_len: %ld", data_len)); + DBUG_PRINT("error",("data_len: %lu", data_len)); result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS : LOG_READ_TOO_LARGE); goto end; @@ -1372,7 +1373,7 @@ failed my_b_read")); */ DBUG_RETURN(0); } - uint data_len = uint4korr(head + EVENT_LEN_OFFSET); + ulong data_len = uint4korr(head + EVENT_LEN_OFFSET); char *buf= 0; const char *error= 0; Log_event *res= 0; @@ -1381,7 +1382,8 @@ failed my_b_read")); uint max_allowed_packet= thd ? slave_max_allowed_packet:~(uint)0; #endif - if (data_len > max_allowed_packet) + if (data_len > max(max_allowed_packet, + opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER)) { error = "Event too big"; goto err; @@ -1415,7 +1417,7 @@ failed my_b_read")); { DBUG_ASSERT(error != 0); sql_print_error("Error in Log_event::read_log_event(): " - "'%s', data_len: %d, event_type: %d", + "'%s', data_len: %lu, event_type: %d", error,data_len,head[EVENT_TYPE_OFFSET]); my_free(buf); /* From 409709ec7edc0dd6eb725e766f0d4c52192accfc Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 31 Jul 2015 20:33:10 +0200 Subject: [PATCH 43/47] compilation error on windows --- sql/sql_class.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 8d51120e428ed..68563ab12b247 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -58,7 +58,7 @@ class Rows_log_event; class Sroutine_hash_entry; class User_level_lock; class user_var_entry; -class Trans_binlog_info; +struct Trans_binlog_info; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME }; From 96badb16afcf8a6ae3d03918419fc51ace4be236 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 31 Jul 2015 22:09:46 +0200 Subject: [PATCH 44/47] MDEV-7821 Server crashes in Item_func_group_concat::fix_fields on 2nd execution of PS Correct fix for this bug. The problem was that Item_func_group_concat() was calling setup_order(), passing args as the second argument, ref_pointer_array. While ref_pointer_array should have free space at the end, as setup_order() can append elements to it. In this particular case args[] elements were overwritten when setup_order() was pushing new elements into ref_pointer_array. --- sql/item_sum.cc | 16 ++++++++++------ sql/item_sum.h | 1 + 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index a24307b131bf0..9000289fd339d 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3300,8 +3300,6 @@ void Item_func_group_concat::cleanup() from Item_func_group_concat::setup() to point to runtime created objects, we need to reset them back to the original arguments of the function. - - The very same applies to args array. */ ORDER **order_ptr= order; for (uint i= 0; i < arg_count_order; i++) @@ -3309,7 +3307,6 @@ void Item_func_group_concat::cleanup() (*order_ptr)->item= &args[arg_count_field + i]; order_ptr++; } - memcpy(args, orig_args, sizeof(Item *) * arg_count); DBUG_VOID_RETURN; } @@ -3517,9 +3514,16 @@ bool Item_func_group_concat::setup(THD *thd) "all_fields". The resulting field list is used as input to create tmp table columns. */ - if (arg_count_order && - setup_order(thd, args, context->table_list, list, all_fields, *order)) - DBUG_RETURN(TRUE); + if (arg_count_order) + { + uint n_elems= arg_count_order + all_fields.elements; + ref_pointer_array= static_cast(thd->alloc(sizeof(Item*) * n_elems)); + memcpy(ref_pointer_array, args, arg_count * sizeof(Item*)); + if (!ref_pointer_array || + setup_order(thd, ref_pointer_array, context->table_list, list, + all_fields, *order)) + DBUG_RETURN(TRUE); + } count_field_types(select_lex, tmp_table_param, all_fields, 0); tmp_table_param->force_copy_fields= force_copy_fields; diff --git a/sql/item_sum.h b/sql/item_sum.h index f074cc6c822b1..86093f5d4f58d 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1394,6 +1394,7 @@ class Item_func_group_concat : public Item_sum String *separator; TREE tree_base; TREE *tree; + Item **ref_pointer_array; /** If DISTINCT is used with this GROUP_CONCAT, this member is used to filter From 1b0c81c917c215fad107d66c75cc2eb282bd8f4e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Aug 2015 15:02:14 +0200 Subject: [PATCH 45/47] 5.5.44-37.3 --- storage/xtradb/buf/buf0buf.c | 6 ++++- storage/xtradb/dict/dict0dict.c | 6 ++--- storage/xtradb/handler/ha_innodb.cc | 34 +++++++++++++++++++---------- storage/xtradb/include/univ.i | 2 +- storage/xtradb/srv/srv0start.c | 4 ++-- storage/xtradb/sync/sync0arr.c | 7 +++--- storage/xtradb/trx/trx0trx.c | 4 ++-- 7 files changed, 39 insertions(+), 24 deletions(-) diff --git a/storage/xtradb/buf/buf0buf.c b/storage/xtradb/buf/buf0buf.c index f86e4ad4a19da..fbfa7830c76bc 100644 --- a/storage/xtradb/buf/buf0buf.c +++ b/storage/xtradb/buf/buf0buf.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -1666,6 +1666,10 @@ buf_pool_watch_set( /* buf_pool->watch is protected by zip_mutex for now */ mutex_enter(&buf_pool->zip_mutex); + + /* The maximum number of purge threads should never exceed + BUF_POOL_WATCH_SIZE. So there is no way for purge thread + instance to hold a watch when setting another watch. */ for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) { bpage = &buf_pool->watch[i]; diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c index 546cead76d2a8..26e361966d687 100644 --- a/storage/xtradb/dict/dict0dict.c +++ b/storage/xtradb/dict/dict0dict.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -2664,7 +2664,7 @@ dict_foreign_remove_from_cache( rbt = foreign->referenced_table->referenced_rbt; - if (rbt != NULL) { + if (rbt != NULL && foreign->id != NULL) { const ib_rbt_node_t* node = rbt_lookup(rbt, foreign->id); dict_foreign_t* val = *(dict_foreign_t**) node->value; @@ -2683,7 +2683,7 @@ dict_foreign_remove_from_cache( foreign); rbt = foreign->foreign_table->foreign_rbt; - if (rbt != NULL) { + if (rbt != NULL && foreign->id != NULL) { const ib_rbt_node_t* node = rbt_lookup(rbt, foreign->id); dict_foreign_t* val = *(dict_foreign_t**) node->value; diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 88816d322a923..69d8830d07d7a 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. @@ -8934,6 +8934,13 @@ ha_innobase::estimate_rows_upper_bound(void) estimate = 2 * local_data_file_length / dict_index_calc_min_rec_len(index); + /* Set num_rows less than MERGEBUFF to simulate the case where we do + not have enough space to merge the externally sorted file blocks. */ + DBUG_EXECUTE_IF("set_num_rows_lt_MERGEBUFF", + estimate = 2; + DBUG_SET("-d,set_num_rows_lt_MERGEBUFF"); + ); + prebuilt->trx->op_info = (char*)""; DBUG_RETURN((ha_rows) estimate); @@ -9218,17 +9225,6 @@ ha_innobase::info_low( prebuilt->trx->op_info = "returning various info to MySQL"; } - my_snprintf(path, sizeof(path), "%s/%s%s", - mysql_data_home, ib_table->name, reg_ext); - - unpack_filename(path,path); - - /* Note that we do not know the access time of the table, - nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ - - if (os_file_get_status(path,&stat_info)) { - stats.create_time = (ulong) stat_info.ctime; - } } if (flag & HA_STATUS_VARIABLE) { @@ -9425,6 +9421,20 @@ ha_innobase::info_low( } dict_table_stats_unlock(ib_table, RW_S_LATCH); + + my_snprintf(path, sizeof(path), "%s/%s%s", + mysql_data_home, + table->s->normalized_path.str, + reg_ext); + + unpack_filename(path,path); + + /* Note that we do not know the access time of the table, + nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ + + if (os_file_get_status(path,&stat_info)) { + stats.create_time = (ulong) stat_info.ctime; + } } if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index 13ada8f106893..58bf30e8fe687 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -64,7 +64,7 @@ component, i.e. we show M.N.P as M.N */ (INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR) #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 37.2 +#define PERCONA_INNODB_VERSION 37.3 #endif #define INNODB_VERSION_STR MYSQL_SERVER_VERSION diff --git a/storage/xtradb/srv/srv0start.c b/storage/xtradb/srv/srv0start.c index 85a3818d77e57..2d39cddbcce63 100644 --- a/storage/xtradb/srv/srv0start.c +++ b/storage/xtradb/srv/srv0start.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2009, Percona Inc. @@ -2466,9 +2466,9 @@ innobase_shutdown_for_mysql(void) ibuf_close(); log_shutdown(); - lock_sys_close(); trx_sys_file_format_close(); trx_sys_close(); + lock_sys_close(); mutex_free(&srv_monitor_file_mutex); mutex_free(&srv_dict_tmpfile_mutex); diff --git a/storage/xtradb/sync/sync0arr.c b/storage/xtradb/sync/sync0arr.c index db50304a70b27..75af1475c7138 100644 --- a/storage/xtradb/sync/sync0arr.c +++ b/storage/xtradb/sync/sync0arr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -1025,8 +1025,9 @@ sync_array_output_info( ulint i; fprintf(file, - "OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n", - (long) arr->res_count, (long) arr->sg_count); + "OS WAIT ARRAY INFO: reservation count " ULINTPF + ", signal count " ULINTPF "\n", + arr->res_count, arr->sg_count); i = 0; count = 0; diff --git a/storage/xtradb/trx/trx0trx.c b/storage/xtradb/trx/trx0trx.c index 09f425cfa5560..7ed79d4c7f47a 100644 --- a/storage/xtradb/trx/trx0trx.c +++ b/storage/xtradb/trx/trx0trx.c @@ -769,9 +769,9 @@ trx_lists_init_at_db_start(void) " anyway.\n"); trx->state = TRX_ACTIVE; - trx_reserve_descriptor( - trx); } + + trx_reserve_descriptor(trx); } else { trx->state = TRX_COMMITTED_IN_MEMORY; From 877de3af28b49029be1f6191f202f8e0b4fb1733 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 30 Jul 2015 22:08:39 +0300 Subject: [PATCH 46/47] MDEV-8554: Server crashes in base_list_iterator::next_fast ... THD::>save_prep_leaf_list was set to true by multi-table update statements with mergeable selects and never reset. Make every statement reset it at start. --- mysql-test/r/view.result | 15 +++++++++++++++ mysql-test/t/view.test | 21 +++++++++++++++++++++ sql/sql_parse.cc | 2 ++ 3 files changed, 38 insertions(+) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index cbacb2c1ef8d0..431e8d2d862f6 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -5429,6 +5429,21 @@ View Create View character_set_client collation_connection v2 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select (`t1`.`b` + 1) AS `c` from `t1` latin1 latin1_swedish_ci drop view v2; drop table t1; +# +# MDEV-8554: Server crashes in base_list_iterator::next_fast on 1st execution of PS with a multi-table update +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3),(4); +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES (5),(6); +CREATE OR REPLACE ALGORITHM=MERGE VIEW v3 AS SELECT * FROM t3; +PREPARE stmt FROM 'UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM t3 )'; +UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM v3 ); +EXECUTE stmt; +DROP TABLE t1, t2, t3; +DROP VIEW v3; # ----------------------------------------------------------------- # -- End of 5.5 tests. # ----------------------------------------------------------------- diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 0432db0ba31ed..ca70cd1efa78a 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -5380,6 +5380,27 @@ show create view v2; drop view v2; drop table t1; +--echo # +--echo # MDEV-8554: Server crashes in base_list_iterator::next_fast on 1st execution of PS with a multi-table update +--echo # +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2); # Not necessary, the table can be empty + +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3),(4); # Not necessary, the table can be empty + +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES (5),(6); # Not necessary, the table can be empty + +CREATE OR REPLACE ALGORITHM=MERGE VIEW v3 AS SELECT * FROM t3; + +PREPARE stmt FROM 'UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM t3 )'; +UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM v3 ); +EXECUTE stmt; + +DROP TABLE t1, t2, t3; +DROP VIEW v3; + --echo # ----------------------------------------------------------------- --echo # -- End of 5.5 tests. --echo # ----------------------------------------------------------------- diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4ad3f9ab8c56a..8d61e09c80d8b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5653,6 +5653,8 @@ void THD::reset_for_next_command() thd->reset_current_stmt_binlog_format_row(); thd->binlog_unsafe_warning_flags= 0; + thd->save_prep_leaf_list= false; + DBUG_PRINT("debug", ("is_current_stmt_binlog_format_row(): %d", thd->is_current_stmt_binlog_format_row())); From fa51f70dc68fe2f3afe943e2c81fcbdb34f16cad Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 4 Aug 2015 23:42:44 +0200 Subject: [PATCH 47/47] correct the NULL-pointer test --- sql/item_sum.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 9000289fd339d..adf48f6feecf2 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3518,9 +3518,10 @@ bool Item_func_group_concat::setup(THD *thd) { uint n_elems= arg_count_order + all_fields.elements; ref_pointer_array= static_cast(thd->alloc(sizeof(Item*) * n_elems)); + if (!ref_pointer_array) + DBUG_RETURN(TRUE); memcpy(ref_pointer_array, args, arg_count * sizeof(Item*)); - if (!ref_pointer_array || - setup_order(thd, ref_pointer_array, context->table_list, list, + if (setup_order(thd, ref_pointer_array, context->table_list, list, all_fields, *order)) DBUG_RETURN(TRUE); }