From 52d9a4d3d660d9b90e6523eb05a1be4cd9f0607c Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 10 Sep 2009 11:14:23 +0200 Subject: [PATCH 001/274] WL#4571, Enable Key cache defined for a partition to enable more scalability on partitioned MyISAM tables among other things --- BUILD/build_mccge.sh | 2 +- sql/ha_partition.cc | 58 ++++++++++++++++++++++++++- sql/ha_partition.h | 5 ++- sql/partition_element.h | 3 +- sql/sql_partition.cc | 2 +- sql/sql_table.cc | 1 + sql/sql_yacc.yy | 87 +++++++++++++++++++++++++++++++---------- 7 files changed, 132 insertions(+), 26 deletions(-) diff --git a/BUILD/build_mccge.sh b/BUILD/build_mccge.sh index ad3e728453c..379ca1b2c68 100755 --- a/BUILD/build_mccge.sh +++ b/BUILD/build_mccge.sh @@ -556,7 +556,7 @@ parse_package() package="pro" ;; extended ) - package="" + package="extended" ;; cge ) package="cge" diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ac8c46ec4e3..dc5ce9f4bdc 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -847,9 +847,12 @@ int ha_partition::rename_partitions(const char *path) #define ANALYZE_PARTS 2 #define CHECK_PARTS 3 #define REPAIR_PARTS 4 +#define ASSIGN_KEYCACHE_PARTS 5 +#define PRELOAD_KEYS_PARTS 6 static const char *opt_op_name[]= {NULL, - "optimize", "analyze", "check", "repair" }; + "optimize", "analyze", "check", "repair", + "assign_to_keycache", "preload_keys"}; /* Optimize table @@ -934,7 +937,44 @@ int ha_partition::repair(THD *thd, HA_CHECK_OPT *check_opt) DBUG_RETURN(handle_opt_partitions(thd, check_opt, REPAIR_PARTS)); } +/** + Assign to keycache + @param thd Thread object + @param check_opt Check/analyze/repair/optimize options + + @return + @retval >0 Error + @retval 0 Success +*/ + +int ha_partition::assign_to_keycache(THD *thd, HA_CHECK_OPT *check_opt) +{ + DBUG_ENTER("ha_partition::assign_to_keycache"); + + DBUG_RETURN(handle_opt_partitions(thd, check_opt, ASSIGN_KEYCACHE_PARTS)); +} + + +/** + Preload to keycache + + @param thd Thread object + @param check_opt Check/analyze/repair/optimize options + + @return + @retval >0 Error + @retval 0 Success +*/ + +int ha_partition::preload_keys(THD *thd, HA_CHECK_OPT *check_opt) +{ + DBUG_ENTER("ha_partition::preload_keys"); + + DBUG_RETURN(handle_opt_partitions(thd, check_opt, PRELOAD_KEYS_PARTS)); +} + + /* Handle optimize/analyze/check/repair of one partition @@ -965,6 +1005,10 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, error= file->ha_check(thd, check_opt); else if (flag == REPAIR_PARTS) error= file->ha_repair(thd, check_opt); + else if (flag == ASSIGN_KEYCACHE_PARTS) + error= file->assign_to_keycache(thd, check_opt); + else if (flag == PRELOAD_KEYS_PARTS) + error= file->preload_keys(thd, check_opt); else { DBUG_ASSERT(FALSE); @@ -1094,6 +1138,12 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, "Subpartition %s returned error", sub_elem->partition_name); } + /* reset part_state for the remaining partitions */ + do + { + if (part_elem->part_state == PART_ADMIN) + part_elem->part_state= PART_NORMAL; + } while (part_elem= part_it++); DBUG_RETURN(error); } } while (++j < no_subparts); @@ -1120,6 +1170,12 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, opt_op_name[flag], "Partition %s returned error", part_elem->partition_name); } + /* reset part_state for the remaining partitions */ + do + { + if (part_elem->part_state == PART_ADMIN) + part_elem->part_state= PART_NORMAL; + } while (part_elem= part_it++); DBUG_RETURN(error); } } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 8a81a759e2a..2f0ce6e7910 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1061,12 +1061,13 @@ public: virtual int backup(TD* thd, HA_CHECK_OPT *check_opt); virtual int restore(THD* thd, HA_CHECK_OPT *check_opt); - virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt); - virtual int preload_keys(THD *thd, HA_CHECK_OPT *check_opt); virtual int dump(THD* thd, int fd = -1); virtual int net_read_dump(NET* net); virtual uint checksum() const; */ + /* Enabled keycache for performance reasons, WL#4571 */ + virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt); + virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt); /* ------------------------------------------------------------------------- diff --git a/sql/partition_element.h b/sql/partition_element.h index 905bc38165b..bede5264c71 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -32,7 +32,8 @@ enum partition_state { PART_REORGED_DROPPED= 5, PART_CHANGED= 6, PART_IS_CHANGED= 7, - PART_IS_ADDED= 8 + PART_IS_ADDED= 8, + PART_ADMIN= 9 }; /* diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 61766e5c509..1c109362a0b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4151,7 +4151,7 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info, /* Mark the partition. I.e mark the partition as a partition to be "changed" by - analyzing/optimizing/rebuilding/checking/repairing + analyzing/optimizing/rebuilding/checking/repairing/... */ no_parts_found++; part_elem->part_state= part_state; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 81d00f46000..9b8c23ce5e9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4521,6 +4521,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, /* Set up which partitions that should be processed if ALTER TABLE t ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION .. + CACHE INDEX/LOAD INDEX for specified partitions */ Alter_info *alter_info= &lex->alter_info; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4ed9946a334..54458c53570 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1261,7 +1261,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); slave master_def master_defs master_file_def slave_until_opts repair restore backup analyze check start checksum field_list field_list_item field_spec kill column_def key_def - keycache_list assign_to_keycache preload_list preload_keys + keycache_list keycache_list_or_parts assign_to_keycache + assign_to_keycache_parts + preload_list preload_list_or_parts preload_keys preload_keys_parts select_item_list select_item values_list no_braces opt_limit_clause delete_limit_clause fields opt_values values procedure_list procedure_list2 procedure_item @@ -3747,17 +3749,9 @@ opt_partitioning: ; partitioning: - PARTITION_SYM + PARTITION_SYM have_partitioning { -#ifdef WITH_PARTITION_STORAGE_ENGINE LEX *lex= Lex; - LEX_STRING partition_name={C_STRING_WITH_LEN("partition")}; - if (!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN)) - { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), - "--skip-partition"); - MYSQL_YYABORT; - } lex->part_info= new partition_info(); if (!lex->part_info) { @@ -3768,16 +3762,29 @@ partitioning: { lex->alter_info.flags|= ALTER_PARTITION; } -#else - my_error(ER_FEATURE_DISABLED, MYF(0), - "partitioning", "--with-partition"); - MYSQL_YYABORT; -#endif - } partition ; +have_partitioning: + /* empty */ + { +#ifdef WITH_PARTITION_STORAGE_ENGINE + LEX_STRING partition_name={C_STRING_WITH_LEN("partition")}; + if (!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN)) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), + "--skip-partition"); + MYSQL_YYABORT; + } +#else + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), + "--skip-partition"); + MYSQL_YYABORT; +#endif + } + ; + partition_entry: PARTITION_SYM { @@ -5437,7 +5444,6 @@ alter: if (!lex->select_lex.add_table_to_list(thd, $4, NULL, TL_OPTION_UPDATING)) MYSQL_YYABORT; - lex->alter_info.reset(); lex->col_list.empty(); lex->select_lex.init_order(); lex->select_lex.db= @@ -6296,14 +6302,23 @@ table_to_table: ; keycache: - CACHE_SYM INDEX_SYM keycache_list IN_SYM key_cache_name + CACHE_SYM INDEX_SYM + { + Lex->alter_info.reset(); + } + keycache_list_or_parts IN_SYM key_cache_name { LEX *lex=Lex; lex->sql_command= SQLCOM_ASSIGN_TO_KEYCACHE; - lex->ident= $5; + lex->ident= $6; } ; +keycache_list_or_parts: + keycache_list + | assign_to_keycache_parts + ; + keycache_list: assign_to_keycache | keycache_list ',' assign_to_keycache @@ -6318,6 +6333,15 @@ assign_to_keycache: } ; +assign_to_keycache_parts: + table_ident adm_partition cache_keys_spec + { + if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ, + Select->pop_index_hints())) + MYSQL_YYABORT; + } + ; + key_cache_name: ident { $$= $1; } | DEFAULT { $$ = default_key_cache_base; } @@ -6328,11 +6352,17 @@ preload: { LEX *lex=Lex; lex->sql_command=SQLCOM_PRELOAD_KEYS; + lex->alter_info.reset(); } - preload_list + preload_list_or_parts {} ; +preload_list_or_parts: + preload_keys_parts + | preload_list + ; + preload_list: preload_keys | preload_list ',' preload_keys @@ -6347,6 +6377,23 @@ preload_keys: } ; +preload_keys_parts: + table_ident adm_partition cache_keys_spec opt_ignore_leaves + { + if (!Select->add_table_to_list(YYTHD, $1, NULL, $4, TL_READ, + Select->pop_index_hints())) + MYSQL_YYABORT; + } + ; + +adm_partition: + PARTITION_SYM have_partitioning + { + Lex->alter_info.flags|= ALTER_ADMIN_PARTITION; + } + '(' all_or_alt_part_name_list ')' + ; + cache_keys_spec: { Lex->select_lex.alloc_index_hints(YYTHD); From d0d52e9f11ab7bad11d34d207139a26f26dd362c Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 10 Sep 2009 11:15:39 +0200 Subject: [PATCH 002/274] WL#4444 Added TRUNCATE partition support, fixes bug#19405 and bug #35111 --- BUILD/build_mccge.sh | 2 +- mysql-test/r/partition_truncate.result | 18 ++ mysql-test/suite/parts/inc/partition_mgm.inc | 90 ++++++++++ .../parts/r/partition_mgm_lc0_archive.result | 12 ++ .../parts/r/partition_mgm_lc0_innodb.result | 164 ++++++++++++++++++ .../parts/r/partition_mgm_lc0_memory.result | 164 ++++++++++++++++++ .../parts/r/partition_mgm_lc0_myisam.result | 164 ++++++++++++++++++ .../parts/r/partition_mgm_lc0_ndb.result | 12 ++ .../parts/r/partition_mgm_lc1_archive.result | 12 ++ .../parts/r/partition_mgm_lc1_innodb.result | 164 ++++++++++++++++++ .../parts/r/partition_mgm_lc1_memory.result | 164 ++++++++++++++++++ .../parts/r/partition_mgm_lc1_myisam.result | 164 ++++++++++++++++++ .../parts/r/partition_mgm_lc1_ndb.result | 12 ++ .../parts/r/partition_mgm_lc2_archive.result | 12 ++ .../parts/r/partition_mgm_lc2_innodb.result | 164 ++++++++++++++++++ .../parts/r/partition_mgm_lc2_memory.result | 164 ++++++++++++++++++ .../parts/r/partition_mgm_lc2_myisam.result | 164 ++++++++++++++++++ .../parts/r/partition_mgm_lc2_ndb.result | 12 ++ .../parts/t/partition_mgm_lc0_archive.test | 1 + .../suite/parts/t/partition_mgm_lc0_ndb.test | 2 + .../parts/t/partition_mgm_lc1_archive.test | 1 + .../suite/parts/t/partition_mgm_lc1_ndb.test | 2 + .../parts/t/partition_mgm_lc2_archive.test | 1 + .../suite/parts/t/partition_mgm_lc2_ndb.test | 2 + mysql-test/t/partition_truncate.test | 26 +++ sql/ha_partition.cc | 83 ++++++++- sql/handler.cc | 3 + sql/partition_element.h | 3 +- sql/sql_delete.cc | 19 +- sql/sql_partition.cc | 2 + sql/sql_table.cc | 2 +- sql/sql_yacc.yy | 16 +- 32 files changed, 1810 insertions(+), 11 deletions(-) create mode 100644 mysql-test/r/partition_truncate.result create mode 100644 mysql-test/t/partition_truncate.test diff --git a/BUILD/build_mccge.sh b/BUILD/build_mccge.sh index ad3e728453c..379ca1b2c68 100755 --- a/BUILD/build_mccge.sh +++ b/BUILD/build_mccge.sh @@ -556,7 +556,7 @@ parse_package() package="pro" ;; extended ) - package="" + package="extended" ;; cge ) package="cge" diff --git a/mysql-test/r/partition_truncate.result b/mysql-test/r/partition_truncate.result new file mode 100644 index 00000000000..8f594a319df --- /dev/null +++ b/mysql-test/r/partition_truncate.result @@ -0,0 +1,18 @@ +drop table if exists t1, t2, t3, t4; +create table t1 (a int) +partition by list (a) +(partition p1 values in (0)); +alter table t1 truncate partition p1,p1; +ERROR HY000: Incorrect partition name +alter table t1 truncate partition p0; +ERROR HY000: Incorrect partition name +drop table t1; +create table t1 (a int) +partition by list (a) +subpartition by hash (a) +subpartitions 1 +(partition p1 values in (1) +(subpartition sp1)); +alter table t1 truncate partition sp1; +ERROR HY000: Incorrect partition name +drop table t1; diff --git a/mysql-test/suite/parts/inc/partition_mgm.inc b/mysql-test/suite/parts/inc/partition_mgm.inc index 1ab548222a8..9dfa2b2ffb3 100644 --- a/mysql-test/suite/parts/inc/partition_mgm.inc +++ b/mysql-test/suite/parts/inc/partition_mgm.inc @@ -13,6 +13,7 @@ # part_optA-D Extra partitioning options (E.g. INDEX/DATA DIR) # # # # have_bug33158 NDB case insensitive create, but case sensitive rename # +# no_truncate No support for truncate partition # #------------------------------------------------------------------------------# # Original Author: mattiasj # # Original Date: 2008-06-27 # @@ -518,6 +519,95 @@ DROP TABLE TableA; } # End of $can_only_key +if ($no_truncate) +{ +--echo # Verify that TRUNCATE PARTITION gives error +eval CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, + b VARCHAR(255)) +ENGINE = $engine +PARTITION BY KEY (a) +(PARTITION LT1000, + PARTITION LT2000, + PARTITION MAX); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +--error ER_PARTITION_MGMT_ON_NONPARTITIONED, ER_ILLEGAL_HA +ALTER TABLE t1 TRUNCATE PARTITION MAX; +} +if (!$no_truncate) +{ +--echo # Testing TRUNCATE PARTITION +eval CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, + b VARCHAR(255)) +ENGINE = $engine +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), + PARTITION LT2000 VALUES LESS THAN (2000), + PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +SELECT * FROM t1 ORDER BY a; +ALTER TABLE t1 ANALYZE PARTITION MAX; +--echo # Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +--echo # Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +--echo # Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +--echo # Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +--echo # Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +--echo # Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +--echo # Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +--echo # Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +--echo # Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +--echo # Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +--echo # Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +--echo # Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +DROP TABLE t1; +} --echo # Cleaning up before exit eval USE $old_db; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc0_archive.result b/mysql-test/suite/parts/r/partition_mgm_lc0_archive.result index 30ff27df298..4f623813386 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc0_archive.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc0_archive.result @@ -915,6 +915,18 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=ARCHIVE DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Verify that TRUNCATE PARTITION gives error +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'Archive' +PARTITION BY KEY (a) +(PARTITION LT1000, +PARTITION LT2000, +PARTITION MAX); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +ALTER TABLE t1 TRUNCATE PARTITION MAX; +Got one of the listed errors # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc0_innodb.result b/mysql-test/suite/parts/r/partition_mgm_lc0_innodb.result index cd55ffbad03..19f16780d13 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc0_innodb.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc0_innodb.result @@ -915,6 +915,170 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Testing TRUNCATE PARTITION +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'InnoDB' +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), +PARTITION LT2000 VALUES LESS THAN (2000), +PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` varchar(255) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB AUTO_INCREMENT=2002 DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000) ENGINE = InnoDB, + PARTITION LT2000 VALUES LESS THAN (2000) ENGINE = InnoDB, + PARTITION MAX VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ +SELECT * FROM t1 ORDER BY a; +a b +1 First +2 Second +999 Last in LT1000 +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First in MAX +2001 Second in MAX +ALTER TABLE t1 ANALYZE PARTITION MAX; +Table Op Msg_type Msg_text +MySQL_Test_DB.t1 analyze status OK +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +2008 First after TRUNCATE LT2000 (4) +DROP TABLE t1; # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc0_memory.result b/mysql-test/suite/parts/r/partition_mgm_lc0_memory.result index faf776e03a3..69a43b64d87 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc0_memory.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc0_memory.result @@ -915,6 +915,170 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=MEMORY DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Testing TRUNCATE PARTITION +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'Memory' +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), +PARTITION LT2000 VALUES LESS THAN (2000), +PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` varchar(255) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MEMORY AUTO_INCREMENT=2002 DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000) ENGINE = MEMORY, + PARTITION LT2000 VALUES LESS THAN (2000) ENGINE = MEMORY, + PARTITION MAX VALUES LESS THAN MAXVALUE ENGINE = MEMORY) */ +SELECT * FROM t1 ORDER BY a; +a b +1 First +2 Second +999 Last in LT1000 +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First in MAX +2001 Second in MAX +ALTER TABLE t1 ANALYZE PARTITION MAX; +Table Op Msg_type Msg_text +MySQL_Test_DB.t1 analyze note The storage engine for the table doesn't support analyze +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +2008 First after TRUNCATE LT2000 (4) +DROP TABLE t1; # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc0_myisam.result b/mysql-test/suite/parts/r/partition_mgm_lc0_myisam.result index 827f7a15c24..9b4e85be9d0 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc0_myisam.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc0_myisam.result @@ -915,6 +915,170 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Testing TRUNCATE PARTITION +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'MyISAM' +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), +PARTITION LT2000 VALUES LESS THAN (2000), +PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` varchar(255) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM AUTO_INCREMENT=2002 DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000) ENGINE = MyISAM, + PARTITION LT2000 VALUES LESS THAN (2000) ENGINE = MyISAM, + PARTITION MAX VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +SELECT * FROM t1 ORDER BY a; +a b +1 First +2 Second +999 Last in LT1000 +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First in MAX +2001 Second in MAX +ALTER TABLE t1 ANALYZE PARTITION MAX; +Table Op Msg_type Msg_text +MySQL_Test_DB.t1 analyze status OK +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +2008 First after TRUNCATE LT2000 (4) +DROP TABLE t1; # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc0_ndb.result b/mysql-test/suite/parts/r/partition_mgm_lc0_ndb.result index 45b674638e7..15b3f424527 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc0_ndb.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc0_ndb.result @@ -181,6 +181,18 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=ndbcluster DEFAULT CHARSET=latin1 # Cleaning up after KEY PARTITIONING test DROP TABLE TableA; +# Verify that TRUNCATE PARTITION gives error +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'NDBCluster' +PARTITION BY KEY (a) +(PARTITION LT1000, +PARTITION LT2000, +PARTITION MAX); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +ALTER TABLE t1 TRUNCATE PARTITION MAX; +Got one of the listed errors # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc1_archive.result b/mysql-test/suite/parts/r/partition_mgm_lc1_archive.result index 443453a2d70..4cd8cafa3ee 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc1_archive.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc1_archive.result @@ -882,6 +882,18 @@ TableA CREATE TABLE `tablea` ( ) ENGINE=ARCHIVE DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Verify that TRUNCATE PARTITION gives error +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'Archive' +PARTITION BY KEY (a) +(PARTITION LT1000, +PARTITION LT2000, +PARTITION MAX); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +ALTER TABLE t1 TRUNCATE PARTITION MAX; +Got one of the listed errors # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc1_innodb.result b/mysql-test/suite/parts/r/partition_mgm_lc1_innodb.result index 49ccc7b1808..952f4136cb6 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc1_innodb.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc1_innodb.result @@ -882,6 +882,170 @@ TableA CREATE TABLE `tablea` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Testing TRUNCATE PARTITION +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'InnoDB' +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), +PARTITION LT2000 VALUES LESS THAN (2000), +PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` varchar(255) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB AUTO_INCREMENT=2002 DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000) ENGINE = InnoDB, + PARTITION LT2000 VALUES LESS THAN (2000) ENGINE = InnoDB, + PARTITION MAX VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ +SELECT * FROM t1 ORDER BY a; +a b +1 First +2 Second +999 Last in LT1000 +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First in MAX +2001 Second in MAX +ALTER TABLE t1 ANALYZE PARTITION MAX; +Table Op Msg_type Msg_text +mysql_test_db.t1 analyze status OK +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +2008 First after TRUNCATE LT2000 (4) +DROP TABLE t1; # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc1_memory.result b/mysql-test/suite/parts/r/partition_mgm_lc1_memory.result index 6f34054428c..435a0d8313e 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc1_memory.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc1_memory.result @@ -882,6 +882,170 @@ TableA CREATE TABLE `tablea` ( ) ENGINE=MEMORY DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Testing TRUNCATE PARTITION +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'Memory' +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), +PARTITION LT2000 VALUES LESS THAN (2000), +PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` varchar(255) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MEMORY AUTO_INCREMENT=2002 DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000) ENGINE = MEMORY, + PARTITION LT2000 VALUES LESS THAN (2000) ENGINE = MEMORY, + PARTITION MAX VALUES LESS THAN MAXVALUE ENGINE = MEMORY) */ +SELECT * FROM t1 ORDER BY a; +a b +1 First +2 Second +999 Last in LT1000 +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First in MAX +2001 Second in MAX +ALTER TABLE t1 ANALYZE PARTITION MAX; +Table Op Msg_type Msg_text +mysql_test_db.t1 analyze note The storage engine for the table doesn't support analyze +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +2008 First after TRUNCATE LT2000 (4) +DROP TABLE t1; # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc1_myisam.result b/mysql-test/suite/parts/r/partition_mgm_lc1_myisam.result index ac230e29c66..3a90ce4d73c 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc1_myisam.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc1_myisam.result @@ -882,6 +882,170 @@ TableA CREATE TABLE `tablea` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Testing TRUNCATE PARTITION +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'MyISAM' +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), +PARTITION LT2000 VALUES LESS THAN (2000), +PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` varchar(255) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM AUTO_INCREMENT=2002 DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000) ENGINE = MyISAM, + PARTITION LT2000 VALUES LESS THAN (2000) ENGINE = MyISAM, + PARTITION MAX VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +SELECT * FROM t1 ORDER BY a; +a b +1 First +2 Second +999 Last in LT1000 +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First in MAX +2001 Second in MAX +ALTER TABLE t1 ANALYZE PARTITION MAX; +Table Op Msg_type Msg_text +mysql_test_db.t1 analyze status OK +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +2008 First after TRUNCATE LT2000 (4) +DROP TABLE t1; # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc1_ndb.result b/mysql-test/suite/parts/r/partition_mgm_lc1_ndb.result index 0a53e1b4a9b..1d221caa163 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc1_ndb.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc1_ndb.result @@ -219,6 +219,18 @@ TableA CREATE TABLE `tablea` ( ) ENGINE=ndbcluster DEFAULT CHARSET=latin1 # Cleaning up after KEY PARTITIONING test DROP TABLE TableA; +# Verify that TRUNCATE PARTITION gives error +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'NDBCluster' +PARTITION BY KEY (a) +(PARTITION LT1000, +PARTITION LT2000, +PARTITION MAX); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +ALTER TABLE t1 TRUNCATE PARTITION MAX; +Got one of the listed errors # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc2_archive.result b/mysql-test/suite/parts/r/partition_mgm_lc2_archive.result index fc0390c238d..6e8abfef06d 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc2_archive.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc2_archive.result @@ -882,6 +882,18 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=ARCHIVE DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Verify that TRUNCATE PARTITION gives error +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'Archive' +PARTITION BY KEY (a) +(PARTITION LT1000, +PARTITION LT2000, +PARTITION MAX); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +ALTER TABLE t1 TRUNCATE PARTITION MAX; +Got one of the listed errors # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc2_innodb.result b/mysql-test/suite/parts/r/partition_mgm_lc2_innodb.result index da111137068..8e42bc9eb62 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc2_innodb.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc2_innodb.result @@ -882,6 +882,170 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Testing TRUNCATE PARTITION +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'InnoDB' +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), +PARTITION LT2000 VALUES LESS THAN (2000), +PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` varchar(255) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB AUTO_INCREMENT=2002 DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000) ENGINE = InnoDB, + PARTITION LT2000 VALUES LESS THAN (2000) ENGINE = InnoDB, + PARTITION MAX VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ +SELECT * FROM t1 ORDER BY a; +a b +1 First +2 Second +999 Last in LT1000 +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First in MAX +2001 Second in MAX +ALTER TABLE t1 ANALYZE PARTITION MAX; +Table Op Msg_type Msg_text +mysql_test_db.t1 analyze status OK +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +2008 First after TRUNCATE LT2000 (4) +DROP TABLE t1; # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc2_memory.result b/mysql-test/suite/parts/r/partition_mgm_lc2_memory.result index a1716ea36c8..24047912ab1 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc2_memory.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc2_memory.result @@ -882,6 +882,170 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=MEMORY DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Testing TRUNCATE PARTITION +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'Memory' +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), +PARTITION LT2000 VALUES LESS THAN (2000), +PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` varchar(255) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MEMORY AUTO_INCREMENT=2002 DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000) ENGINE = MEMORY, + PARTITION LT2000 VALUES LESS THAN (2000) ENGINE = MEMORY, + PARTITION MAX VALUES LESS THAN MAXVALUE ENGINE = MEMORY) */ +SELECT * FROM t1 ORDER BY a; +a b +1 First +2 Second +999 Last in LT1000 +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First in MAX +2001 Second in MAX +ALTER TABLE t1 ANALYZE PARTITION MAX; +Table Op Msg_type Msg_text +mysql_test_db.t1 analyze note The storage engine for the table doesn't support analyze +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +2008 First after TRUNCATE LT2000 (4) +DROP TABLE t1; # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc2_myisam.result b/mysql-test/suite/parts/r/partition_mgm_lc2_myisam.result index 6bdfa149de0..7a61a811ea3 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc2_myisam.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc2_myisam.result @@ -882,6 +882,170 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 # Cleaning up after LIST PARTITIONING test DROP TABLE TableA; +# Testing TRUNCATE PARTITION +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'MyISAM' +PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000), +PARTITION LT2000 VALUES LESS THAN (2000), +PARTITION MAX VALUES LESS THAN MAXVALUE); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL AUTO_INCREMENT, + `b` varchar(255) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM AUTO_INCREMENT=2002 DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (a) +(PARTITION LT1000 VALUES LESS THAN (1000) ENGINE = MyISAM, + PARTITION LT2000 VALUES LESS THAN (2000) ENGINE = MyISAM, + PARTITION MAX VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +SELECT * FROM t1 ORDER BY a; +a b +1 First +2 Second +999 Last in LT1000 +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First in MAX +2001 Second in MAX +ALTER TABLE t1 ANALYZE PARTITION MAX; +Table Op Msg_type Msg_text +mysql_test_db.t1 analyze status OK +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (1)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION MAX; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (2)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (3)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION MAX; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE MAX (4)"); +SELECT * FROM t1 WHERE a >= 2000; +a b +2000 First after TRUNCATE MAX (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT1000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT1000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +1000 First in LT2000 +1001 Second in LT2000 +1999 Last in LT2000 +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +# Truncate without FLUSH +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (1)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +# Truncate with FLUSH after +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +FLUSH TABLES; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (2)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +# Truncate with FLUSH before +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (3)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +# Truncate with FLUSH after INSERT +FLUSH TABLES; +ALTER TABLE t1 TRUNCATE PARTITION LT2000; +INSERT INTO t1 VALUES (NULL, "First after TRUNCATE LT2000 (4)"); +SELECT * FROM t1 ORDER BY a; +a b +2000 First after TRUNCATE MAX (4) +2001 First after TRUNCATE LT1000 (1) +2002 First after TRUNCATE LT1000 (2) +2003 First after TRUNCATE LT1000 (3) +2004 First after TRUNCATE LT1000 (4) +2005 First after TRUNCATE LT2000 (1) +2006 First after TRUNCATE LT2000 (2) +2007 First after TRUNCATE LT2000 (3) +2008 First after TRUNCATE LT2000 (4) +DROP TABLE t1; # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/r/partition_mgm_lc2_ndb.result b/mysql-test/suite/parts/r/partition_mgm_lc2_ndb.result index 8b9c5be1fb6..2f5dfe5e08e 100644 --- a/mysql-test/suite/parts/r/partition_mgm_lc2_ndb.result +++ b/mysql-test/suite/parts/r/partition_mgm_lc2_ndb.result @@ -219,6 +219,18 @@ TableA CREATE TABLE `TableA` ( ) ENGINE=ndbcluster DEFAULT CHARSET=latin1 # Cleaning up after KEY PARTITIONING test DROP TABLE TableA; +# Verify that TRUNCATE PARTITION gives error +CREATE TABLE t1 +(a BIGINT AUTO_INCREMENT PRIMARY KEY, +b VARCHAR(255)) +ENGINE = 'NDBCluster' +PARTITION BY KEY (a) +(PARTITION LT1000, +PARTITION LT2000, +PARTITION MAX); +INSERT INTO t1 VALUES (NULL, "First"), (NULL, "Second"), (999, "Last in LT1000"), (NULL, "First in LT2000"), (NULL, "Second in LT2000"), (1999, "Last in LT2000"), (NULL, "First in MAX"), (NULL, "Second in MAX"); +ALTER TABLE t1 TRUNCATE PARTITION MAX; +Got one of the listed errors # Cleaning up before exit USE test; DROP DATABASE MySQL_Test_DB; diff --git a/mysql-test/suite/parts/t/partition_mgm_lc0_archive.test b/mysql-test/suite/parts/t/partition_mgm_lc0_archive.test index 5b4f2568d46..313da329a9f 100644 --- a/mysql-test/suite/parts/t/partition_mgm_lc0_archive.test +++ b/mysql-test/suite/parts/t/partition_mgm_lc0_archive.test @@ -35,6 +35,7 @@ ##### Storage engine to be tested --source include/have_archive.inc let $engine= 'Archive'; +let $no_truncate= 1; #------------------------------------------------------------------------------# # Execute the tests to be applied to all storage engines diff --git a/mysql-test/suite/parts/t/partition_mgm_lc0_ndb.test b/mysql-test/suite/parts/t/partition_mgm_lc0_ndb.test index 686c69cca25..736e45067bc 100644 --- a/mysql-test/suite/parts/t/partition_mgm_lc0_ndb.test +++ b/mysql-test/suite/parts/t/partition_mgm_lc0_ndb.test @@ -41,6 +41,8 @@ let $can_only_key= 1; # Allow hash/list/range partitioning with ndb #SET new=on; let $engine= 'NDBCluster'; +# NDB does not yet support TRUNCATE PARTITION +let $no_truncate= 1; #------------------------------------------------------------------------------# # Execute the tests to be applied to all storage engines diff --git a/mysql-test/suite/parts/t/partition_mgm_lc1_archive.test b/mysql-test/suite/parts/t/partition_mgm_lc1_archive.test index 2bc643db75f..58eef828f06 100644 --- a/mysql-test/suite/parts/t/partition_mgm_lc1_archive.test +++ b/mysql-test/suite/parts/t/partition_mgm_lc1_archive.test @@ -32,6 +32,7 @@ ##### Storage engine to be tested --source include/have_archive.inc let $engine= 'Archive'; +let $no_truncate= 1; #------------------------------------------------------------------------------# # Execute the tests to be applied to all storage engines diff --git a/mysql-test/suite/parts/t/partition_mgm_lc1_ndb.test b/mysql-test/suite/parts/t/partition_mgm_lc1_ndb.test index a70b9b5c41c..ac425eb84ff 100644 --- a/mysql-test/suite/parts/t/partition_mgm_lc1_ndb.test +++ b/mysql-test/suite/parts/t/partition_mgm_lc1_ndb.test @@ -38,6 +38,8 @@ let $can_only_key= 1; # Allow hash/list/range partitioning with ndb #SET new=on; let $engine= 'NDBCluster'; +# NDB does not yet support TRUNCATE PARTITION +let $no_truncate= 1; #------------------------------------------------------------------------------# # Execute the tests to be applied to all storage engines diff --git a/mysql-test/suite/parts/t/partition_mgm_lc2_archive.test b/mysql-test/suite/parts/t/partition_mgm_lc2_archive.test index d0e2591804d..92036178e59 100644 --- a/mysql-test/suite/parts/t/partition_mgm_lc2_archive.test +++ b/mysql-test/suite/parts/t/partition_mgm_lc2_archive.test @@ -32,6 +32,7 @@ ##### Storage engine to be tested --source include/have_archive.inc let $engine= 'Archive'; +let $no_truncate= 1; #------------------------------------------------------------------------------# # Execute the tests to be applied to all storage engines diff --git a/mysql-test/suite/parts/t/partition_mgm_lc2_ndb.test b/mysql-test/suite/parts/t/partition_mgm_lc2_ndb.test index 67fdfdde70b..725ba3b5e74 100644 --- a/mysql-test/suite/parts/t/partition_mgm_lc2_ndb.test +++ b/mysql-test/suite/parts/t/partition_mgm_lc2_ndb.test @@ -37,6 +37,8 @@ let $can_only_key= 1; # Allow hash/list/range partitioning with ndb #SET new=on; let $engine= 'NDBCluster'; +# NDB does not yet support TRUNCATE PARTITION +let $no_truncate= 1; #------------------------------------------------------------------------------# # Execute the tests to be applied to all storage engines diff --git a/mysql-test/t/partition_truncate.test b/mysql-test/t/partition_truncate.test new file mode 100644 index 00000000000..93b9cf62d14 --- /dev/null +++ b/mysql-test/t/partition_truncate.test @@ -0,0 +1,26 @@ +# +# Simple tests to verify truncate partition syntax +# +--source include/have_partition.inc +--disable_warnings +drop table if exists t1, t2, t3, t4; +--enable_warnings + +create table t1 (a int) +partition by list (a) +(partition p1 values in (0)); +--error ER_WRONG_PARTITION_NAME +alter table t1 truncate partition p1,p1; +--error ER_WRONG_PARTITION_NAME +alter table t1 truncate partition p0; +drop table t1; + +create table t1 (a int) +partition by list (a) +subpartition by hash (a) +subpartitions 1 +(partition p1 values in (1) + (subpartition sp1)); +--error ER_WRONG_PARTITION_NAME +alter table t1 truncate partition sp1; +drop table t1; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ac8c46ec4e3..83a2a3064d5 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1062,7 +1062,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, it should only do named partitions, otherwise all partitions */ if (!(thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION) || - part_elem->part_state == PART_CHANGED) + part_elem->part_state == PART_ADMIN) { if (m_is_sub_partitioned) { @@ -1123,6 +1123,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, DBUG_RETURN(error); } } + part_elem->part_state= PART_NORMAL; } } while (++i < no_parts); DBUG_RETURN(FALSE); @@ -3202,6 +3203,9 @@ int ha_partition::delete_row(const uchar *buf) Called from sql_delete.cc by mysql_delete(). Called from sql_select.cc by JOIN::reinit(). Called from sql_union.cc by st_select_lex_unit::exec(). + + Also used for handle ALTER TABLE t TRUNCATE PARTITION ... + NOTE: auto increment value will be truncated in that partition as well! */ int ha_partition::delete_all_rows() @@ -3214,11 +3218,84 @@ int ha_partition::delete_all_rows() if (thd->lex->sql_command == SQLCOM_TRUNCATE) { + Alter_info *alter_info= &thd->lex->alter_info; HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; + /* TRUNCATE also means resetting auto_increment */ lock_auto_increment(); ha_data->next_auto_inc_val= 0; ha_data->auto_inc_initialized= FALSE; unlock_auto_increment(); + if (alter_info->flags & ALTER_ADMIN_PARTITION) + { + /* ALTER TABLE t TRUNCATE PARTITION ... */ + List_iterator part_it(m_part_info->partitions); + int saved_error= 0; + uint no_parts= m_part_info->no_parts; + uint no_subparts= m_part_info->no_subparts; + uint i= 0; + uint no_parts_set= alter_info->partition_names.elements; + uint no_parts_found= set_part_state(alter_info, m_part_info, + PART_ADMIN); + if (no_parts_set != no_parts_found && + (!(alter_info->flags & ALTER_ALL_PARTITION))) + DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND); + + /* + Cannot return HA_ERR_WRONG_COMMAND here without correct pruning + since that whould delete the whole table row by row in sql_delete.cc + */ + bitmap_clear_all(&m_part_info->used_partitions); + do + { + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_ADMIN) + { + if (m_is_sub_partitioned) + { + List_iterator + subpart_it(part_elem->subpartitions); + partition_element *sub_elem; + uint j= 0, part; + do + { + sub_elem= subpart_it++; + part= i * no_subparts + j; + bitmap_set_bit(&m_part_info->used_partitions, part); + if (!saved_error) + { + DBUG_PRINT("info", ("truncate subpartition %u (%s)", + part, sub_elem->partition_name)); + if ((error= m_file[part]->ha_delete_all_rows())) + saved_error= error; + /* If not reset_auto_increment is supported, just accept it */ + if (!saved_error && + (error= m_file[part]->ha_reset_auto_increment(0)) && + error != HA_ERR_WRONG_COMMAND) + saved_error= error; + } + } while (++j < no_subparts); + } + else + { + DBUG_PRINT("info", ("truncate partition %u (%s)", i, + part_elem->partition_name)); + bitmap_set_bit(&m_part_info->used_partitions, i); + if (!saved_error) + { + if ((error= m_file[i]->ha_delete_all_rows()) && !saved_error) + saved_error= error; + /* If not reset_auto_increment is supported, just accept it */ + if (!saved_error && + (error= m_file[i]->ha_reset_auto_increment(0)) && + error != HA_ERR_WRONG_COMMAND) + saved_error= error; + } + } + part_elem->part_state= PART_NORMAL; + } + } while (++i < no_parts); + DBUG_RETURN(saved_error); + } truncate= TRUE; } file= m_file; @@ -5842,12 +5919,14 @@ enum row_type ha_partition::get_row_type() const void ha_partition::print_error(int error, myf errflag) { + THD *thd= ha_thd(); DBUG_ENTER("ha_partition::print_error"); /* Should probably look for my own errors first */ DBUG_PRINT("enter", ("error: %d", error)); - if (error == HA_ERR_NO_PARTITION_FOUND) + if (error == HA_ERR_NO_PARTITION_FOUND && + thd->lex->sql_command != SQLCOM_TRUNCATE) m_part_info->print_no_partition_found(table); else m_file[m_last_part]->print_error(error, errflag); diff --git a/sql/handler.cc b/sql/handler.cc index 0e83d2911f2..97e49ef2157 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2742,6 +2742,9 @@ void handler::print_error(int error, myf errflag) case HA_ERR_TABLE_NEEDS_UPGRADE: textno=ER_TABLE_NEEDS_UPGRADE; break; + case HA_ERR_NO_PARTITION_FOUND: + textno=ER_WRONG_PARTITION_NAME; + break; case HA_ERR_TABLE_READONLY: textno= ER_OPEN_AS_READONLY; break; diff --git a/sql/partition_element.h b/sql/partition_element.h index 905bc38165b..bede5264c71 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -32,7 +32,8 @@ enum partition_state { PART_REORGED_DROPPED= 5, PART_CHANGED= 6, PART_IS_CHANGED= 7, - PART_IS_ADDED= 8 + PART_IS_ADDED= 8, + PART_ADMIN= 9 }; /* diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d2f90fa9288..ee272dad341 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1075,6 +1075,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) { handlerton *table_type= table->s->db_type(); TABLE_SHARE *share= table->s; + /* Note that a temporary table cannot be partitioned */ if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE)) goto trunc_by_del; @@ -1113,8 +1114,22 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) table_list->db, table_list->table_name); DBUG_RETURN(TRUE); } - if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd, table_type), - HTON_CAN_RECREATE)) +#ifdef WITH_PARTITION_STORAGE_ENGINE + /* + TODO: Add support for TRUNCATE PARTITION for NDB and other engines + supporting native partitioning + */ + if (table_type != DB_TYPE_PARTITION_DB && + thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION) + { + my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); + DBUG_RETURN(TRUE); + } +#endif + if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd, + table_type), + HTON_CAN_RECREATE) || + thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION) goto trunc_by_del; if (lock_and_wait_for_table_name(thd, table_list)) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 61766e5c509..2fbdde9c4aa 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4158,6 +4158,8 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info, DBUG_PRINT("info", ("Setting part_state to %u for partition %s", part_state, part_elem->partition_name)); } + else + part_elem->part_state= PART_NORMAL; } while (++part_count < tab_part_info->no_parts); return no_parts_found; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 81d00f46000..4a1050b897d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4534,7 +4534,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, uint no_parts_found; uint no_parts_opt= alter_info->partition_names.elements; no_parts_found= set_part_state(alter_info, table->table->part_info, - PART_CHANGED); + PART_ADMIN); if (no_parts_found != no_parts_opt && (!(alter_info->flags & ALTER_ALL_PARTITION))) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4ed9946a334..72ec879a7c8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5671,7 +5671,7 @@ alter_commands: all_or_alt_part_name_list { LEX *lex= Lex; - lex->sql_command = SQLCOM_OPTIMIZE; + lex->sql_command= SQLCOM_OPTIMIZE; lex->alter_info.flags|= ALTER_ADMIN_PARTITION; lex->no_write_to_binlog= $3; lex->check_opt.init(); @@ -5681,7 +5681,7 @@ alter_commands: all_or_alt_part_name_list { LEX *lex= Lex; - lex->sql_command = SQLCOM_ANALYZE; + lex->sql_command= SQLCOM_ANALYZE; lex->alter_info.flags|= ALTER_ADMIN_PARTITION; lex->no_write_to_binlog= $3; lex->check_opt.init(); @@ -5689,7 +5689,7 @@ alter_commands: | CHECK_SYM PARTITION_SYM all_or_alt_part_name_list { LEX *lex= Lex; - lex->sql_command = SQLCOM_CHECK; + lex->sql_command= SQLCOM_CHECK; lex->alter_info.flags|= ALTER_ADMIN_PARTITION; lex->check_opt.init(); } @@ -5698,7 +5698,7 @@ alter_commands: all_or_alt_part_name_list { LEX *lex= Lex; - lex->sql_command = SQLCOM_REPAIR; + lex->sql_command= SQLCOM_REPAIR; lex->alter_info.flags|= ALTER_ADMIN_PARTITION; lex->no_write_to_binlog= $3; lex->check_opt.init(); @@ -5711,6 +5711,13 @@ alter_commands: lex->no_write_to_binlog= $3; lex->alter_info.no_parts= $4; } + | TRUNCATE_SYM PARTITION_SYM all_or_alt_part_name_list + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_TRUNCATE; + lex->alter_info.flags|= ALTER_ADMIN_PARTITION; + lex->check_opt.init(); + } | reorg_partition_rule ; @@ -9758,6 +9765,7 @@ truncate: { LEX* lex= Lex; lex->sql_command= SQLCOM_TRUNCATE; + lex->alter_info.reset(); lex->select_lex.options= 0; lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; lex->select_lex.init_order(); From 63e56390a3f1a4f80642932a790ab74f28de8010 Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Thu, 10 Sep 2009 03:18:29 -0600 Subject: [PATCH 003/274] WL#2110 (SIGNAL) WL#2265 (RESIGNAL) Manual merge of SIGNAL and RESIGNAL to mysql-trunk-signal, plus required dependencies. --- include/my_sys.h | 31 +- libmysqld/CMakeLists.txt | 1 + libmysqld/Makefile.am | 2 +- libmysqld/emb_qcache.cc | 3 +- libmysqld/lib_sql.cc | 40 +- mysql-test/r/bigint.result | 4 +- mysql-test/r/cast.result | 2 +- mysql-test/r/ctype_utf8.result | 14 +- mysql-test/r/date_formats.result | 64 +- mysql-test/r/func_compress.result | 14 +- mysql-test/r/func_encrypt.result | 8 +- mysql-test/r/func_gconcat.result | 64 +- mysql-test/r/func_math.result | 10 +- mysql-test/r/func_str.result | 256 +- mysql-test/r/join_outer.result | 12 +- mysql-test/r/merge.result | 2 +- mysql-test/r/myisam-system.result | 2 +- mysql-test/r/partition.result | 1 - mysql-test/r/ps.result | 4 + mysql-test/r/query_cache.result | 8 +- mysql-test/r/signal.result | 2362 +++++++++++++++ mysql-test/r/signal_code.result | 35 + mysql-test/r/signal_demo1.result | 270 ++ mysql-test/r/signal_demo2.result | 197 ++ mysql-test/r/signal_demo3.result | 143 + mysql-test/r/signal_sqlmode.result | 86 + mysql-test/r/sp-dynamic.result | 8 - mysql-test/r/sp-vars.result | 70 - mysql-test/r/sp.result | 51 +- mysql-test/r/sp_notembedded.result | 2 + mysql-test/r/strict.result | 52 +- mysql-test/r/trigger.result | 14 +- mysql-test/r/type_newdecimal.result | 76 +- mysql-test/r/view.result | 20 +- mysql-test/suite/binlog/r/binlog_index.result | 2 +- .../suite/binlog/r/binlog_unsafe.result | 27 - mysql-test/suite/innodb/r/innodb-zip.result | 26 - mysql-test/suite/ndb/r/ndb_bitfield.result | 4 +- mysql-test/suite/ndb/r/ndb_dd_basic.result | 6 +- mysql-test/suite/ndb/r/ndb_dd_ddl.result | 2 +- mysql-test/suite/ndb/r/ndb_gis.result | 4 +- .../suite/ndb/r/ndb_partition_error.result | 2 +- mysql-test/suite/ndb/r/ndb_row_format.result | 2 +- mysql-test/suite/ndb/r/ndb_single_user.result | 10 +- mysql-test/suite/rpl/r/rpl_EE_err.result | 2 +- .../suite/rpl/r/rpl_row_sp007_innodb.result | 2 - mysql-test/t/func_gconcat.test | 32 + mysql-test/t/signal.test | 2685 +++++++++++++++++ mysql-test/t/signal_code.test | 57 + mysql-test/t/signal_demo1.test | 345 +++ mysql-test/t/signal_demo2.test | 207 ++ mysql-test/t/signal_demo3.test | 159 + mysql-test/t/signal_sqlmode.test | 123 + mysys/my_error.c | 18 +- mysys/my_messnc.c | 6 +- mysys/my_static.c | 6 +- sql/CMakeLists.txt | 1 + sql/Makefile.am | 4 +- sql/authors.h | 1 + sql/event_scheduler.cc | 13 +- sql/field.cc | 29 +- sql/ha_ndbcluster.cc | 18 +- sql/ha_ndbcluster_binlog.cc | 68 +- sql/handler.cc | 27 +- sql/item.cc | 5 +- sql/item_func.cc | 12 +- sql/item_strfunc.cc | 18 +- sql/item_sum.cc | 45 +- sql/item_sum.h | 5 +- sql/item_timefunc.cc | 2 +- sql/lex.h | 14 + sql/log.cc | 39 +- sql/log_event.cc | 35 +- sql/log_event_old.cc | 12 +- sql/my_decimal.cc | 6 +- sql/mysql_priv.h | 4 + sql/mysqld.cc | 82 +- sql/protocol.cc | 93 +- sql/protocol.h | 4 +- sql/repl_failsafe.cc | 2 +- sql/rpl_rli.cc | 4 +- sql/set_var.cc | 8 +- sql/share/errmsg.txt | 36 +- sql/slave.cc | 41 +- sql/sp.cc | 22 +- sql/sp_head.cc | 33 +- sql/sp_pcontext.cc | 3 +- sql/sp_pcontext.h | 2 +- sql/sp_rcontext.cc | 94 +- sql/sp_rcontext.h | 61 +- sql/sql_acl.cc | 26 +- sql/sql_base.cc | 30 +- sql/sql_cache.cc | 4 +- sql/sql_class.cc | 398 +-- sql/sql_class.h | 349 +-- sql/sql_connect.cc | 4 +- sql/sql_derived.cc | 6 +- sql/sql_error.cc | 650 +++- sql/sql_error.h | 520 +++- sql/sql_insert.cc | 30 +- sql/sql_lex.h | 98 +- sql/sql_load.cc | 41 +- sql/sql_parse.cc | 47 +- sql/sql_prepare.cc | 46 +- sql/sql_repl.cc | 4 +- sql/sql_select.cc | 10 +- sql/sql_servers.cc | 2 +- sql/sql_show.cc | 28 +- sql/sql_signal.cc | 510 ++++ sql/sql_signal.h | 152 + sql/sql_table.cc | 43 +- sql/sql_tablespace.cc | 4 +- sql/sql_update.cc | 7 +- sql/sql_yacc.yy | 281 +- sql/table.cc | 24 +- sql/thr_malloc.cc | 7 +- sql/time.cc | 2 +- sql/tztime.cc | 2 +- sql/unireg.cc | 21 +- storage/myisammrg/ha_myisammrg.cc | 2 +- 120 files changed, 10269 insertions(+), 1577 deletions(-) create mode 100644 mysql-test/r/signal.result create mode 100644 mysql-test/r/signal_code.result create mode 100644 mysql-test/r/signal_demo1.result create mode 100644 mysql-test/r/signal_demo2.result create mode 100644 mysql-test/r/signal_demo3.result create mode 100644 mysql-test/r/signal_sqlmode.result create mode 100644 mysql-test/t/signal.test create mode 100644 mysql-test/t/signal_code.test create mode 100644 mysql-test/t/signal_demo1.test create mode 100644 mysql-test/t/signal_demo2.test create mode 100644 mysql-test/t/signal_demo3.test create mode 100644 mysql-test/t/signal_sqlmode.test create mode 100644 sql/sql_signal.cc create mode 100644 sql/sql_signal.h diff --git a/include/my_sys.h b/include/my_sys.h index 222564e0b44..473633ce6ef 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -39,6 +39,17 @@ extern int NEAR my_errno; /* Last error in mysys */ #define MYSYS_PROGRAM_DONT_USE_CURSES() { error_handler_hook = my_message_no_curses; mysys_uses_curses=0;} #define MY_INIT(name); { my_progname= name; my_init(); } +/** + Max length of an error message generated by mysys utilities. + Some mysys functions produce error messages. These mostly go + to stderr. + This constant defines the size of the buffer used to format + the message. It should be kept in sync with MYSQL_ERRMSG_SIZE, + since sometimes mysys errors are stored in the server diagnostics + area, and we would like to avoid unexpected truncation. +*/ +#define MYSYS_ERRMSG_SIZE (512) + #define MY_FILE_ERROR ((size_t) -1) /* General bitmaps for my_func's */ @@ -89,8 +100,6 @@ extern int NEAR my_errno; /* Last error in mysys */ #define ME_COLOUR2 ((2 << ME_HIGHBYTE)) #define ME_COLOUR3 ((3 << ME_HIGHBYTE)) #define ME_FATALERROR 1024 /* Fatal statement error */ -#define ME_NO_WARNING_FOR_ERROR 2048 /* Don't push a warning for error */ -#define ME_NO_SP_HANDLER 4096 /* Don't call stored routine error handlers */ /* Bits in last argument to fn_format */ #define MY_REPLACE_DIR 1 /* replace dir in name with 'dir' */ @@ -209,8 +218,8 @@ extern int errno; /* declare errno */ extern char *home_dir; /* Home directory for user */ extern const char *my_progname; /* program-name (printed in errors) */ extern char NEAR curr_dir[]; /* Current directory for user */ -extern int (*error_handler_hook)(uint my_err, const char *str,myf MyFlags); -extern int (*fatal_error_handler_hook)(uint my_err, const char *str, +extern void (*error_handler_hook)(uint my_err, const char *str,myf MyFlags); +extern void (*fatal_error_handler_hook)(uint my_err, const char *str, myf MyFlags); extern uint my_file_limit; extern ulong my_thread_stack_size; @@ -645,15 +654,15 @@ extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); extern int my_sync(File fd, myf my_flags); extern int my_sync_dir(const char *dir_name, myf my_flags); extern int my_sync_dir_by_file(const char *file_name, myf my_flags); -extern int my_error _VARARGS((int nr,myf MyFlags, ...)); -extern int my_printf_error _VARARGS((uint my_err, const char *format, - myf MyFlags, ...)) - ATTRIBUTE_FORMAT(printf, 2, 4); +extern void my_error _VARARGS((int nr,myf MyFlags, ...)); +extern void my_printf_error _VARARGS((uint my_err, const char *format, + myf MyFlags, ...)) + ATTRIBUTE_FORMAT(printf, 2, 4); extern int my_error_register(const char **errmsgs, int first, int last); extern const char **my_error_unregister(int first, int last); -extern int my_message(uint my_err, const char *str,myf MyFlags); -extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags); -extern int my_message_curses(uint my_err, const char *str,myf MyFlags); +extern void my_message(uint my_err, const char *str,myf MyFlags); +extern void my_message_no_curses(uint my_err, const char *str,myf MyFlags); +extern void my_message_curses(uint my_err, const char *str,myf MyFlags); extern my_bool my_init(void); extern void my_end(int infoflag); extern int my_redel(const char *from, const char *to, int MyFlags); diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 8500d73863a..b31082b438a 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -139,6 +139,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc ../sql/partition_info.cc ../sql/sql_connect.cc ../sql/scheduler.cc ../sql/event_parse_data.cc + ./sql/sql_signal.cc ${GEN_SOURCES} ${LIB_SOURCES}) diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 171009c34f6..80a7c74a266 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -77,7 +77,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \ sql_tablespace.cc \ rpl_injector.cc my_user.c partition_info.cc \ - sql_servers.cc event_parse_data.cc + sql_servers.cc event_parse_data.cc sql_signal.cc libmysqld_int_a_SOURCES= $(libmysqld_sources) nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources) diff --git a/libmysqld/emb_qcache.cc b/libmysqld/emb_qcache.cc index b4eddf39c1f..5cbced8a8ff 100644 --- a/libmysqld/emb_qcache.cc +++ b/libmysqld/emb_qcache.cc @@ -483,7 +483,8 @@ int emb_load_querycache_result(THD *thd, Querycache_stream *src) *prev_row= NULL; data->embedded_info->prev_ptr= prev_row; return_ok: - net_send_eof(thd, thd->server_status, thd->total_warn_count); + net_send_eof(thd, thd->server_status, + thd->warning_info->statement_warn_count()); DBUG_RETURN(0); err: DBUG_RETURN(1); diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index d4a200c07b2..64822f8fad6 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -112,7 +112,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, /* Clear result variables */ thd->clear_error(); - thd->main_da.reset_diagnostics_area(); + thd->stmt_da->reset_diagnostics_area(); mysql->affected_rows= ~(my_ulonglong) 0; mysql->field_count= 0; net_clear_error(net); @@ -217,7 +217,7 @@ static my_bool emb_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) stmt->stmt_id= thd->client_stmt_id; stmt->param_count= thd->client_param_count; stmt->field_count= 0; - mysql->warning_count= thd->total_warn_count; + mysql->warning_count= thd->warning_info->statement_warn_count(); if (thd->first_data) { @@ -402,7 +402,7 @@ static void emb_free_embedded_thd(MYSQL *mysql) static const char * emb_read_statistics(MYSQL *mysql) { THD *thd= (THD*)mysql->thd; - return thd->is_error() ? thd->main_da.message() : ""; + return thd->is_error() ? thd->stmt_da->message() : ""; } @@ -703,9 +703,10 @@ int check_embedded_connection(MYSQL *mysql, const char *db) err: { NET *net= &mysql->net; - strmake(net->last_error, thd->main_da.message(), sizeof(net->last_error)-1); + strmake(net->last_error, thd->stmt_da->message(), + sizeof(net->last_error)-1); memcpy(net->sqlstate, - mysql_errno_to_sqlstate(thd->main_da.sql_errno()), + mysql_errno_to_sqlstate(thd->stmt_da->sql_errno()), sizeof(net->sqlstate)-1); } return result; @@ -729,8 +730,8 @@ void THD::clear_data_list() void THD::clear_error() { - if (main_da.is_error()) - main_da.reset_diagnostics_area(); + if (stmt_da->is_error()) + stmt_da->reset_diagnostics_area(); } static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length, @@ -804,7 +805,7 @@ MYSQL_DATA *THD::alloc_new_dataset() static bool -write_eof_packet(THD *thd, uint server_status, uint total_warn_count) +write_eof_packet(THD *thd, uint server_status, uint statement_warn_count) { if (!thd->mysql) // bootstrap file handling return FALSE; @@ -821,7 +822,7 @@ write_eof_packet(THD *thd, uint server_status, uint total_warn_count) is cleared between substatements, and mysqltest gets confused */ thd->cur_data->embedded_info->warning_count= - (thd->spcont ? 0 : min(total_warn_count, 65535)); + (thd->spcont ? 0 : min(statement_warn_count, 65535)); return FALSE; } @@ -978,7 +979,8 @@ bool Protocol::send_fields(List *list, uint flags) } if (flags & SEND_EOF) - write_eof_packet(thd, thd->server_status, thd->total_warn_count); + write_eof_packet(thd, thd->server_status, + thd->warning_info->statement_warn_count()); DBUG_RETURN(prepare_for_send(list)); err: @@ -1040,25 +1042,24 @@ bool Protocol_binary::write() bool net_send_ok(THD *thd, - uint server_status, uint total_warn_count, - ha_rows affected_rows, ulonglong id, const char *message) + uint server_status, uint statement_warn_count, + ulonglong affected_rows, ulonglong id, const char *message) { DBUG_ENTER("emb_net_send_ok"); MYSQL_DATA *data; - bool error; MYSQL *mysql= thd->mysql; if (!mysql) // bootstrap file handling DBUG_RETURN(FALSE); if (!(data= thd->alloc_new_dataset())) - return TRUE; + DBUG_RETURN(TRUE); data->embedded_info->affected_rows= affected_rows; data->embedded_info->insert_id= id; if (message) strmake(data->embedded_info->info, message, sizeof(data->embedded_info->info)-1); - error= write_eof_packet(thd, server_status, total_warn_count); + bool error= write_eof_packet(thd, server_status, statement_warn_count); thd->cur_data= 0; DBUG_RETURN(error); } @@ -1075,15 +1076,16 @@ net_send_ok(THD *thd, */ bool -net_send_eof(THD *thd, uint server_status, uint total_warn_count) +net_send_eof(THD *thd, uint server_status, uint statement_warn_count) { - bool error= write_eof_packet(thd, server_status, total_warn_count); + bool error= write_eof_packet(thd, server_status, statement_warn_count); thd->cur_data= 0; return error; } -bool net_send_error_packet(THD *thd, uint sql_errno, const char *err) +bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, + const char *sqlstate) { MYSQL_DATA *data= thd->cur_data; struct embedded_query_result *ei; @@ -1100,7 +1102,7 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err) ei= data->embedded_info; ei->last_errno= sql_errno; strmake(ei->info, err, sizeof(ei->info)-1); - strmov(ei->sqlstate, mysql_errno_to_sqlstate(sql_errno)); + strmov(ei->sqlstate, sqlstate); ei->server_status= thd->server_status; thd->cur_data= 0; return FALSE; diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index 4a5b8fcf4aa..7c23f1267c2 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -362,12 +362,12 @@ select cast(19999999999999999999 as signed); cast(19999999999999999999 as signed) 9223372036854775807 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select cast(-19999999999999999999 as signed); cast(-19999999999999999999 as signed) -9223372036854775808 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select -9223372036854775808; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def -9223372036854775808 8 20 20 N 32897 0 63 diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index dd61396e485..c53de220b60 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -380,7 +380,7 @@ select cast(s1 as decimal(7,2)) from t1; cast(s1 as decimal(7,2)) 99999.99 Warnings: -Error 1264 Out of range value for column 'cast(s1 as decimal(7,2))' at row 1 +Warning 1264 Out of range value for column 'cast(s1 as decimal(7,2))' at row 1 drop table t1; CREATE TABLE t1 (v varchar(10), tt tinytext, t text, mt mediumtext, lt longtext); diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 6f4ae965ca0..70f976ee9a7 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1631,27 +1631,27 @@ select char(0xff,0x8f using utf8); char(0xff,0x8f using utf8) NULL Warnings: -Error 1300 Invalid utf8 character string: 'FF8F' +Warning 1300 Invalid utf8 character string: 'FF8F' select char(195 using utf8); char(195 using utf8) NULL Warnings: -Error 1300 Invalid utf8 character string: 'C3' +Warning 1300 Invalid utf8 character string: 'C3' select char(196 using utf8); char(196 using utf8) NULL Warnings: -Error 1300 Invalid utf8 character string: 'C4' +Warning 1300 Invalid utf8 character string: 'C4' select char(2557 using utf8); char(2557 using utf8) NULL Warnings: -Error 1300 Invalid utf8 character string: 'FD' +Warning 1300 Invalid utf8 character string: 'FD' select convert(char(0xff,0x8f) using utf8); convert(char(0xff,0x8f) using utf8) NULL Warnings: -Error 1300 Invalid utf8 character string: 'FF8F' +Warning 1300 Invalid utf8 character string: 'FF8F' select hex(convert(char(2557 using latin1) using utf8)); hex(convert(char(2557 using latin1) using utf8)) 09C3BD @@ -1815,12 +1815,12 @@ select hex(char(0xFF using utf8)); hex(char(0xFF using utf8)) NULL Warnings: -Error 1300 Invalid utf8 character string: 'FF' +Warning 1300 Invalid utf8 character string: 'FF' select hex(convert(0xFF using utf8)); hex(convert(0xFF using utf8)) NULL Warnings: -Error 1300 Invalid utf8 character string: 'FF' +Warning 1300 Invalid utf8 character string: 'FF' select hex(_utf8 0x616263FF); ERROR HY000: Invalid utf8 character string: 'FF' select hex(_utf8 X'616263FF'); diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result index 7e185daa668..b0b8316fe33 100644 --- a/mysql-test/r/date_formats.result +++ b/mysql-test/r/date_formats.result @@ -89,7 +89,7 @@ select STR_TO_DATE('2004.12.12 22.30.61','%Y.%m.%d %T'); STR_TO_DATE('2004.12.12 22.30.61','%Y.%m.%d %T') NULL Warnings: -Error 1411 Incorrect time value: '22.30.61' for function str_to_date +Warning 1411 Incorrect time value: '22.30.61' for function str_to_date create table t1 (date char(30), format char(30) not null); insert into t1 values ('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'), @@ -361,21 +361,21 @@ Tuesday 52 2001 %W %u %x NULL 7 53 1998 %w %u %Y NULL NULL %m.%d.%Y NULL Warnings: -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12.123456' for function str_to_date -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AM' for function str_to_date -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AN' for function str_to_date -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date -Error 1411 Incorrect datetime value: '10:20:10AM' for function str_to_date -Error 1411 Incorrect datetime value: '15 Septembei 2001' for function str_to_date -Error 1411 Incorrect datetime value: '15 Ju 2001' for function str_to_date -Error 1411 Incorrect datetime value: 'Sund 15 MA' for function str_to_date -Error 1411 Incorrect datetime value: 'Thursdai 12 1998' for function str_to_date -Error 1411 Incorrect datetime value: 'Sunday 01 2001' for function str_to_date -Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date -Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date -Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date -Error 1411 Incorrect datetime value: '7 53 1998' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12.123456' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12AM' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12AN' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date +Warning 1411 Incorrect datetime value: '10:20:10AM' for function str_to_date +Warning 1411 Incorrect datetime value: '15 Septembei 2001' for function str_to_date +Warning 1411 Incorrect datetime value: '15 Ju 2001' for function str_to_date +Warning 1411 Incorrect datetime value: 'Sund 15 MA' for function str_to_date +Warning 1411 Incorrect datetime value: 'Thursdai 12 1998' for function str_to_date +Warning 1411 Incorrect datetime value: 'Sunday 01 2001' for function str_to_date +Warning 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Warning 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Warning 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Warning 1411 Incorrect datetime value: '7 53 1998' for function str_to_date select date,format,concat(str_to_date(date, format),'') as con from t1; date format con 2003-01-02 10:11:12 PM %Y-%m-%d %H:%i:%S %p NULL @@ -395,21 +395,21 @@ Tuesday 52 2001 %W %u %x NULL 7 53 1998 %w %u %Y NULL NULL %m.%d.%Y NULL Warnings: -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12.123456' for function str_to_date -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AM' for function str_to_date -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AN' for function str_to_date -Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date -Error 1411 Incorrect datetime value: '10:20:10AM' for function str_to_date -Error 1411 Incorrect datetime value: '15 Septembei 2001' for function str_to_date -Error 1411 Incorrect datetime value: '15 Ju 2001' for function str_to_date -Error 1411 Incorrect datetime value: 'Sund 15 MA' for function str_to_date -Error 1411 Incorrect datetime value: 'Thursdai 12 1998' for function str_to_date -Error 1411 Incorrect datetime value: 'Sunday 01 2001' for function str_to_date -Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date -Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date -Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date -Error 1411 Incorrect datetime value: '7 53 1998' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12.123456' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12AM' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12AN' for function str_to_date +Warning 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_date +Warning 1411 Incorrect datetime value: '10:20:10AM' for function str_to_date +Warning 1411 Incorrect datetime value: '15 Septembei 2001' for function str_to_date +Warning 1411 Incorrect datetime value: '15 Ju 2001' for function str_to_date +Warning 1411 Incorrect datetime value: 'Sund 15 MA' for function str_to_date +Warning 1411 Incorrect datetime value: 'Thursdai 12 1998' for function str_to_date +Warning 1411 Incorrect datetime value: 'Sunday 01 2001' for function str_to_date +Warning 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Warning 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Warning 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_date +Warning 1411 Incorrect datetime value: '7 53 1998' for function str_to_date truncate table t1; insert into t1 values ('10:20:10AM', '%h:%i:%s'), @@ -449,7 +449,7 @@ select str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA')); str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA')) NULL Warnings: -Error 1411 Incorrect datetime value: '15-01-2001 12:59:59' for function str_to_date +Warning 1411 Incorrect datetime value: '15-01-2001 12:59:59' for function str_to_date explain extended select makedate(1997,1), addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM"),cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME), maketime(23,11,12),microsecond("1997-12-31 23:59:59.000001"); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used diff --git a/mysql-test/r/func_compress.result b/mysql-test/r/func_compress.result index b4e61d0e4fc..650cc9c2c70 100644 --- a/mysql-test/r/func_compress.result +++ b/mysql-test/r/func_compress.result @@ -65,8 +65,8 @@ NULL 50000 NULL Warnings: -Error 1259 ZLIB: Input data corrupted -Error 1256 Uncompressed data size too large; the maximum size is 1048576 (probably, length of uncompressed data was corrupted) +Warning 1259 ZLIB: Input data corrupted +Warning 1256 Uncompressed data size too large; the maximum size is 1048576 (probably, length of uncompressed data was corrupted) drop table t1; set @@global.max_allowed_packet=1048576*100; select compress(repeat('aaaaaaaaaa', IF(XXX, 10, 10000000))) is null; @@ -96,12 +96,12 @@ explain select * from t1 where uncompress(a) is null; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 1 Warnings: -Error 1259 ZLIB: Input data corrupted +Warning 1259 ZLIB: Input data corrupted select * from t1 where uncompress(a) is null; a foo Warnings: -Error 1259 ZLIB: Input data corrupted +Warning 1259 ZLIB: Input data corrupted explain select *, uncompress(a) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 1 @@ -109,13 +109,13 @@ select *, uncompress(a) from t1; a uncompress(a) foo NULL Warnings: -Error 1259 ZLIB: Input data corrupted +Warning 1259 ZLIB: Input data corrupted select *, uncompress(a), uncompress(a) is null from t1; a uncompress(a) uncompress(a) is null foo NULL 1 Warnings: -Error 1259 ZLIB: Input data corrupted -Error 1259 ZLIB: Input data corrupted +Warning 1259 ZLIB: Input data corrupted +Warning 1259 ZLIB: Input data corrupted drop table t1; CREATE TABLE t1 (c1 INT); INSERT INTO t1 VALUES (1), (1111), (11111); diff --git a/mysql-test/r/func_encrypt.result b/mysql-test/r/func_encrypt.result index 8fbf36b45b9..91ff4e218fb 100644 --- a/mysql-test/r/func_encrypt.result +++ b/mysql-test/r/func_encrypt.result @@ -124,7 +124,7 @@ select des_encrypt("hello",10); des_encrypt("hello",10) NULL Warnings: -Error 1108 Incorrect parameters to procedure 'des_encrypt' +Warning 1108 Incorrect parameters to procedure 'des_encrypt' select des_encrypt(NULL); des_encrypt(NULL) NULL @@ -138,12 +138,12 @@ select des_encrypt(10, NULL); des_encrypt(10, NULL) NULL Warnings: -Error 1108 Incorrect parameters to procedure 'des_encrypt' +Warning 1108 Incorrect parameters to procedure 'des_encrypt' select des_encrypt("hello", NULL); des_encrypt("hello", NULL) NULL Warnings: -Error 1108 Incorrect parameters to procedure 'des_encrypt' +Warning 1108 Incorrect parameters to procedure 'des_encrypt' select des_decrypt("hello",10); des_decrypt("hello",10) hello @@ -177,7 +177,7 @@ select hex(des_decrypt(des_encrypt("hello","hidden"))); hex(des_decrypt(des_encrypt("hello","hidden"))) NULL Warnings: -Error 1108 Incorrect parameters to procedure 'des_decrypt' +Warning 1108 Incorrect parameters to procedure 'des_decrypt' explain extended select des_decrypt(des_encrypt("hello",4),'password2'), des_decrypt(des_encrypt("hello","hidden")); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 3b78851a1b9..ebec186591d 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -153,10 +153,10 @@ grp group_concat(c) 4 5 NULL Warnings: -Warning 1260 1 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 4 was cut by GROUP_CONCAT() show warnings; Level Code Message -Warning 1260 1 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 4 was cut by GROUP_CONCAT() set group_concat_max_len = 1024; select group_concat(sum(c)) from t1 group by grp; ERROR HY000: Invalid use of group function @@ -380,25 +380,29 @@ group_concat(b) bb,c BB,C Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +Warning 1260 Row 4 was cut by GROUP_CONCAT() select group_concat(distinct b) from t1 group by a; group_concat(distinct b) bb,c BB,C Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +Warning 1260 Row 4 was cut by GROUP_CONCAT() select group_concat(b order by b) from t1 group by a; group_concat(b order by b) a,bb A,BB Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 3 was cut by GROUP_CONCAT() +Warning 1260 Row 6 was cut by GROUP_CONCAT() select group_concat(distinct b order by b) from t1 group by a; group_concat(distinct b order by b) a,bb A,BB Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 3 was cut by GROUP_CONCAT() +Warning 1260 Row 6 was cut by GROUP_CONCAT() insert into t1 values (1, concat(repeat('1', 300), '2')), (1, concat(repeat('1', 300), '2')), (1, concat(repeat('0', 300), '1')), (2, concat(repeat('1', 300), '2')), (2, concat(repeat('1', 300), '2')), @@ -426,25 +430,29 @@ group_concat(b) bb,ccc,a,bb,ccc,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,1111111111111111111111111111111111111111111111111111111111111111111111111111111111 BB,CCC,A,BB,CCC,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,1111111111111111111111111111111111111111111111111111111111111111111111111111111111 Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 7 was cut by GROUP_CONCAT() +Warning 1260 Row 14 was cut by GROUP_CONCAT() select group_concat(distinct b) from t1 group by a; group_concat(distinct b) bb,ccc,a,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 BB,CCC,A,1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 5 was cut by GROUP_CONCAT() +Warning 1260 Row 10 was cut by GROUP_CONCAT() select group_concat(b order by b) from t1 group by a; group_concat(b order by b) 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +Warning 1260 Row 4 was cut by GROUP_CONCAT() select group_concat(distinct b order by b) from t1 group by a; group_concat(distinct b order by b) 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +Warning 1260 Row 4 was cut by GROUP_CONCAT() drop table t1; create table t1 (a varchar(255) character set cp1250 collate cp1250_general_ci, b varchar(255) character set koi8r); @@ -751,22 +759,22 @@ SELECT GROUP_CONCAT( a ) FROM t1; GROUP_CONCAT( a ) aaaaaaaaaa,bbbbbbbbb Warnings: -Warning 1260 1 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() SELECT GROUP_CONCAT( DISTINCT a ) FROM t1; GROUP_CONCAT( DISTINCT a ) aaaaaaaaaa,bbbbbbbbb Warnings: -Warning 1260 1 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() SELECT GROUP_CONCAT( a ORDER BY b ) FROM t1; GROUP_CONCAT( a ORDER BY b ) aaaaaaaaaa,bbbbbbbbb Warnings: -Warning 1260 1 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() SELECT GROUP_CONCAT( DISTINCT a ORDER BY b ) FROM t1; GROUP_CONCAT( DISTINCT a ORDER BY b ) aaaaaaaaaa,bbbbbbbbb Warnings: -Warning 1260 1 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() SET group_concat_max_len = DEFAULT; DROP TABLE t1; SET group_concat_max_len= 65535; @@ -979,3 +987,31 @@ GROUP BY t1.a 1 DROP TABLE t1, t2; End of 5.0 tests +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (a VARCHAR(6), b INT); +CREATE TABLE t2 (a VARCHAR(6), b INT); +INSERT INTO t1 VALUES ('111111', 1); +INSERT INTO t1 VALUES ('222222', 2); +INSERT INTO t1 VALUES ('333333', 3); +INSERT INTO t1 VALUES ('444444', 4); +INSERT INTO t1 VALUES ('555555', 5); +SET group_concat_max_len = 5; +SET @old_sql_mode = @@sql_mode, @@sql_mode = 'traditional'; +SELECT GROUP_CONCAT(a), b FROM t1 GROUP BY b LIMIT 3; +GROUP_CONCAT(a) b +11111 1 +22222 2 +33333 3 +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +Warning 1260 Row 3 was cut by GROUP_CONCAT() +INSERT INTO t2 SELECT GROUP_CONCAT(a), b FROM t1 GROUP BY b; +ERROR HY000: Row 1 was cut by GROUP_CONCAT() +UPDATE t1 SET a = '11111' WHERE b = 1; +UPDATE t1 SET a = '22222' WHERE b = 2; +INSERT INTO t2 SELECT GROUP_CONCAT(a), b FROM t1 GROUP BY b; +ERROR HY000: Row 3 was cut by GROUP_CONCAT() +SET group_concat_max_len = DEFAULT; +SET @@sql_mode = @old_sql_mode; +DROP TABLE t1, t2; diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index fd7ef72409e..d8b8a14afc6 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -225,27 +225,27 @@ select ln(-1); ln(-1) NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 select log10(-1); log10(-1) NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 select log2(-1); log2(-1) NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 select log(2,-1); log(2,-1) NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 select log(-2,1); log(-2,1) NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 set sql_mode=''; select round(111,-10); round(111,-10) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index a0c3935fde0..47fd4f2cdad 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1433,7 +1433,7 @@ select benchmark(-1, 1); benchmark(-1, 1) NULL Warnings: -Error 1411 Incorrect count value: '-1' for function benchmark +Warning 1411 Incorrect count value: '-1' for function benchmark set @password="password"; set @my_data="clear text to encode"; select md5(encode(@my_data, "password")); @@ -1533,7 +1533,7 @@ select locate('lo','hello',-18446744073709551615); locate('lo','hello',-18446744073709551615) 0 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select locate('lo','hello',18446744073709551615); locate('lo','hello',18446744073709551615) 0 @@ -1541,22 +1541,22 @@ select locate('lo','hello',-18446744073709551616); locate('lo','hello',-18446744073709551616) 0 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select locate('lo','hello',18446744073709551616); locate('lo','hello',18446744073709551616) 0 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select locate('lo','hello',-18446744073709551617); locate('lo','hello',-18446744073709551617) 0 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select locate('lo','hello',18446744073709551617); locate('lo','hello',18446744073709551617) 0 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select left('hello', 10); left('hello', 10) hello @@ -1588,8 +1588,8 @@ select left('hello', -18446744073709551615); left('hello', -18446744073709551615) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select left('hello', 18446744073709551615); left('hello', 18446744073709551615) hello @@ -1597,26 +1597,26 @@ select left('hello', -18446744073709551616); left('hello', -18446744073709551616) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select left('hello', 18446744073709551616); left('hello', 18446744073709551616) hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select left('hello', -18446744073709551617); left('hello', -18446744073709551617) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select left('hello', 18446744073709551617); left('hello', 18446744073709551617) hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select right('hello', 10); right('hello', 10) hello @@ -1648,8 +1648,8 @@ select right('hello', -18446744073709551615); right('hello', -18446744073709551615) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select right('hello', 18446744073709551615); right('hello', 18446744073709551615) hello @@ -1657,26 +1657,26 @@ select right('hello', -18446744073709551616); right('hello', -18446744073709551616) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select right('hello', 18446744073709551616); right('hello', 18446744073709551616) hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select right('hello', -18446744073709551617); right('hello', -18446744073709551617) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select right('hello', 18446744073709551617); right('hello', 18446744073709551617) hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 2, -1); substring('hello', 2, -1) @@ -1708,8 +1708,8 @@ select substring('hello', -18446744073709551615, 1); substring('hello', -18446744073709551615, 1) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 18446744073709551615, 1); substring('hello', 18446744073709551615, 1) @@ -1717,26 +1717,26 @@ select substring('hello', -18446744073709551616, 1); substring('hello', -18446744073709551616, 1) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 18446744073709551616, 1); substring('hello', 18446744073709551616, 1) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', -18446744073709551617, 1); substring('hello', -18446744073709551617, 1) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 18446744073709551617, 1); substring('hello', 18446744073709551617, 1) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 1, -1); substring('hello', 1, -1) @@ -1762,8 +1762,8 @@ select substring('hello', 1, -18446744073709551615); substring('hello', 1, -18446744073709551615) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 1, 18446744073709551615); substring('hello', 1, 18446744073709551615) hello @@ -1771,26 +1771,26 @@ select substring('hello', 1, -18446744073709551616); substring('hello', 1, -18446744073709551616) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 1, 18446744073709551616); substring('hello', 1, 18446744073709551616) hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 1, -18446744073709551617); substring('hello', 1, -18446744073709551617) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 1, 18446744073709551617); substring('hello', 1, 18446744073709551617) hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', -1, -1); substring('hello', -1, -1) @@ -1816,10 +1816,10 @@ select substring('hello', -18446744073709551615, -18446744073709551615); substring('hello', -18446744073709551615, -18446744073709551615) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 18446744073709551615, 18446744073709551615); substring('hello', 18446744073709551615, 18446744073709551615) @@ -1827,34 +1827,34 @@ select substring('hello', -18446744073709551616, -18446744073709551616); substring('hello', -18446744073709551616, -18446744073709551616) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 18446744073709551616, 18446744073709551616); substring('hello', 18446744073709551616, 18446744073709551616) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', -18446744073709551617, -18446744073709551617); substring('hello', -18446744073709551617, -18446744073709551617) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select substring('hello', 18446744073709551617, 18446744073709551617); substring('hello', 18446744073709551617, 18446744073709551617) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', -1, 1, 'hi'); insert('hello', -1, 1, 'hi') hello @@ -1880,7 +1880,7 @@ select insert('hello', -18446744073709551615, 1, 'hi'); insert('hello', -18446744073709551615, 1, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 18446744073709551615, 1, 'hi'); insert('hello', 18446744073709551615, 1, 'hi') hello @@ -1888,22 +1888,22 @@ select insert('hello', -18446744073709551616, 1, 'hi'); insert('hello', -18446744073709551616, 1, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 18446744073709551616, 1, 'hi'); insert('hello', 18446744073709551616, 1, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', -18446744073709551617, 1, 'hi'); insert('hello', -18446744073709551617, 1, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 18446744073709551617, 1, 'hi'); insert('hello', 18446744073709551617, 1, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 1, -1, 'hi'); insert('hello', 1, -1, 'hi') hi @@ -1929,7 +1929,7 @@ select insert('hello', 1, -18446744073709551615, 'hi'); insert('hello', 1, -18446744073709551615, 'hi') hi Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 1, 18446744073709551615, 'hi'); insert('hello', 1, 18446744073709551615, 'hi') hi @@ -1937,22 +1937,22 @@ select insert('hello', 1, -18446744073709551616, 'hi'); insert('hello', 1, -18446744073709551616, 'hi') hi Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 1, 18446744073709551616, 'hi'); insert('hello', 1, 18446744073709551616, 'hi') hi Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 1, -18446744073709551617, 'hi'); insert('hello', 1, -18446744073709551617, 'hi') hi Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 1, 18446744073709551617, 'hi'); insert('hello', 1, 18446744073709551617, 'hi') hi Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', -1, -1, 'hi'); insert('hello', -1, -1, 'hi') hello @@ -1978,8 +1978,8 @@ select insert('hello', -18446744073709551615, -18446744073709551615, 'hi'); insert('hello', -18446744073709551615, -18446744073709551615, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 18446744073709551615, 18446744073709551615, 'hi'); insert('hello', 18446744073709551615, 18446744073709551615, 'hi') hello @@ -1987,26 +1987,26 @@ select insert('hello', -18446744073709551616, -18446744073709551616, 'hi'); insert('hello', -18446744073709551616, -18446744073709551616, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 18446744073709551616, 18446744073709551616, 'hi'); insert('hello', 18446744073709551616, 18446744073709551616, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', -18446744073709551617, -18446744073709551617, 'hi'); insert('hello', -18446744073709551617, -18446744073709551617, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select insert('hello', 18446744073709551617, 18446744073709551617, 'hi'); insert('hello', 18446744073709551617, 18446744073709551617, 'hi') hello Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select repeat('hello', -1); repeat('hello', -1) @@ -2038,8 +2038,8 @@ select repeat('hello', -18446744073709551615); repeat('hello', -18446744073709551615) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select repeat('hello', 18446744073709551615); repeat('hello', 18446744073709551615) NULL @@ -2049,27 +2049,27 @@ select repeat('hello', -18446744073709551616); repeat('hello', -18446744073709551616) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select repeat('hello', 18446744073709551616); repeat('hello', 18446744073709551616) NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated select repeat('hello', -18446744073709551617); repeat('hello', -18446744073709551617) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select repeat('hello', 18446744073709551617); repeat('hello', 18446744073709551617) NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated select space(-1); space(-1) @@ -2102,8 +2102,8 @@ select space(-18446744073709551615); space(-18446744073709551615) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select space(18446744073709551615); space(18446744073709551615) NULL @@ -2113,27 +2113,27 @@ select space(-18446744073709551616); space(-18446744073709551616) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select space(18446744073709551616); space(18446744073709551616) NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated select space(-18446744073709551617); space(-18446744073709551617) Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select space(18446744073709551617); space(18446744073709551617) NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - truncated select rpad('hello', -1, '1'); rpad('hello', -1, '1') @@ -2166,8 +2166,8 @@ select rpad('hello', -18446744073709551615, '1'); rpad('hello', -18446744073709551615, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select rpad('hello', 18446744073709551615, '1'); rpad('hello', 18446744073709551615, '1') NULL @@ -2177,27 +2177,27 @@ select rpad('hello', -18446744073709551616, '1'); rpad('hello', -18446744073709551616, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select rpad('hello', 18446744073709551616, '1'); rpad('hello', 18446744073709551616, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated select rpad('hello', -18446744073709551617, '1'); rpad('hello', -18446744073709551617, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select rpad('hello', 18446744073709551617, '1'); rpad('hello', 18446744073709551617, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1301 Result of rpad() was larger than max_allowed_packet (1048576) - truncated select lpad('hello', -1, '1'); lpad('hello', -1, '1') @@ -2230,8 +2230,8 @@ select lpad('hello', -18446744073709551615, '1'); lpad('hello', -18446744073709551615, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select lpad('hello', 18446744073709551615, '1'); lpad('hello', 18446744073709551615, '1') NULL @@ -2241,27 +2241,27 @@ select lpad('hello', -18446744073709551616, '1'); lpad('hello', -18446744073709551616, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select lpad('hello', 18446744073709551616, '1'); lpad('hello', 18446744073709551616, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated select lpad('hello', -18446744073709551617, '1'); lpad('hello', -18446744073709551617, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select lpad('hello', 18446744073709551617, '1'); lpad('hello', 18446744073709551617, '1') NULL Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated SET @orig_sql_mode = @@SQL_MODE; SET SQL_MODE=traditional; @@ -2269,12 +2269,12 @@ SELECT CHAR(0xff,0x8f USING utf8); CHAR(0xff,0x8f USING utf8) NULL Warnings: -Error 1300 Invalid utf8 character string: 'FF8F' +Warning 1300 Invalid utf8 character string: 'FF8F' SELECT CHAR(0xff,0x8f USING utf8) IS NULL; CHAR(0xff,0x8f USING utf8) IS NULL 1 Warnings: -Error 1300 Invalid utf8 character string: 'FF8F' +Warning 1300 Invalid utf8 character string: 'FF8F' SET SQL_MODE=@orig_sql_mode; select substring('abc', cast(2 as unsigned int)); substring('abc', cast(2 as unsigned int)) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 1e4fc91b8bd..bc77072f67a 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -942,25 +942,29 @@ group_concat(t1.b,t2.c) aaaaa bbbbb Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; group_concat(t1.b,t2.c) aaaaa bbbbb Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a; group_concat(t1.b,t2.c) aaaaa bbbbb Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a; group_concat(t1.b,t2.c) aaaaa bbbbb Warnings: -Warning 1260 2 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() drop table t1, t2; set group_concat_max_len=default; create table t1 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, art int(11) not null, primary key (gid,x,y)); diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 893ea5acf88..a2248d3d878 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -914,7 +914,7 @@ SELECT * FROM tm1; ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist CHECK TABLE tm1; Table Op Msg_type Msg_text -test.tm1 check Error Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist +test.tm1 check Warning Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist test.tm1 check Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist test.tm1 check error Corrupt ALTER TABLE t2 MODIFY a INT; diff --git a/mysql-test/r/myisam-system.result b/mysql-test/r/myisam-system.result index e0629d955ae..b3ba8066f5c 100644 --- a/mysql-test/r/myisam-system.result +++ b/mysql-test/r/myisam-system.result @@ -2,7 +2,7 @@ drop table if exists t1,t2; create table t1 (a int) engine=myisam; drop table if exists t1; Warnings: -Error 2 Can't find file: 't1' (errno: 2) +Warning 2 Can't find file: 't1' (errno: 2) create table t1 (a int) engine=myisam; drop table t1; Got one of the listed errors diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 2d54a66fe11..a76cb2ba225 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1226,7 +1226,6 @@ COMMIT; END| CALL test.p1(12); Warnings: -Note 1051 Unknown table 't1' Warning 1196 Some non-transactional changed tables couldn't be rolled back CALL test.p1(13); Warnings: diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 1f8a077af40..06e6b8167fd 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -2748,17 +2748,21 @@ Warnings: Note 1051 Unknown table 't1' call proc_1(); Level Code Message +Note 1051 Unknown table 't1' drop table if exists t2; Warnings: Note 1051 Unknown table 't2' call proc_1(); Level Code Message +Note 1051 Unknown table 't2' drop table if exists t1, t2; Warnings: Note 1051 Unknown table 't1' Note 1051 Unknown table 't2' call proc_1(); Level Code Message +Note 1051 Unknown table 't1' +Note 1051 Unknown table 't2' drop procedure proc_1; create function func_1() returns int begin show warnings; return 1; end| ERROR 0A000: Not allowed to return a result set from a function diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 6cabc24d0eb..89057603c3d 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -889,7 +889,7 @@ select group_concat(a) FROM t1 group by b; group_concat(a) 1234567890 Warnings: -Warning 1260 1 line(s) were cut by GROUP_CONCAT() +Warning 1260 Row 1 was cut by GROUP_CONCAT() set group_concat_max_len=1024; select group_concat(a) FROM t1 group by b; group_concat(a) @@ -992,19 +992,19 @@ COUNT(*) 0 Warnings: Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 -Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 0 +Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050328 invalid'; COUNT(*) 0 Warnings: Warning 1292 Incorrect datetime value: '20050328 invalid' for column 'date' at row 1 -Warning 1292 Incorrect datetime value: '20050328 invalid' for column 'date' at row 0 +Warning 1292 Incorrect datetime value: '20050328 invalid' for column 'date' at row 1 SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 invalid'; COUNT(*) 0 Warnings: Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 -Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 0 +Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 diff --git a/mysql-test/r/signal.result b/mysql-test/r/signal.result new file mode 100644 index 00000000000..56140733c33 --- /dev/null +++ b/mysql-test/r/signal.result @@ -0,0 +1,2362 @@ +# +# PART 1: syntax +# +# +# Test every new reserved and non reserved keywords +# +drop table if exists signal_non_reserved; +create table signal_non_reserved ( +class_origin int, +subclass_origin int, +constraint_catalog int, +constraint_schema int, +constraint_name int, +catalog_name int, +schema_name int, +table_name int, +column_name int, +cursor_name int, +message_text int, +sqlcode int +); +drop table signal_non_reserved; +drop table if exists diag_non_reserved; +create table diag_non_reserved ( +diagnostics int, +current int, +stacked int, +exception int +); +drop table diag_non_reserved; +drop table if exists diag_cond_non_reserved; +create table diag_cond_non_reserved ( +condition_identifier int, +condition_number int, +condition_name int, +connection_name int, +message_length int, +message_octet_length int, +parameter_mode int, +parameter_name int, +parameter_ordinal_position int, +returned_sqlstate int, +routine_catalog int, +routine_name int, +routine_schema int, +server_name int, +specific_name int, +trigger_catalog int, +trigger_name int, +trigger_schema int +); +drop table diag_cond_non_reserved; +drop table if exists diag_stmt_non_reserved; +create table diag_stmt_non_reserved ( +number int, +more int, +command_function int, +command_function_code int, +dynamic_function int, +dynamic_function_code int, +row_count int, +transactions_committed int, +transactions_rolled_back int, +transaction_active int +); +drop table diag_stmt_non_reserved; +drop table if exists test_reserved; +create table test_reserved (signal int); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'signal int)' at line 1 +create table test_reserved (resignal int); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'resignal int)' at line 1 +create table test_reserved (condition int); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'condition int)' at line 1 +# +# Test the SIGNAL syntax +# +drop procedure if exists test_invalid; +drop procedure if exists test_signal_syntax; +drop function if exists test_signal_func; +create procedure test_invalid() +begin +SIGNAL; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL foo; +end $$ +ERROR 42000: Undefined CONDITION: foo +create procedure test_invalid() +begin +DECLARE foo CONDITION FOR 1234; +SIGNAL foo; +end $$ +ERROR HY000: SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +SIGNAL SQLSTATE '23000'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +SIGNAL SQLSTATE VALUE '23000'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET CLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET SUBCLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET CONSTRAINT_CATALOG = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET CONSTRAINT_SCHEMA = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET CONSTRAINT_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET CATALOG_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET SCHEMA_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET TABLE_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET COLUMN_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET CURSOR_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MESSAGE_TEXT = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +create procedure test_invalid() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET CLASS_ORIGIN = 'foo', CLASS_ORIGIN = 'bar'; +end $$ +ERROR 42000: Duplicate condition information item 'CLASS_ORIGIN' +create procedure test_invalid() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MESSAGE_TEXT = 'foo', MESSAGE_TEXT = 'bar'; +end $$ +ERROR 42000: Duplicate condition information item 'MESSAGE_TEXT' +create procedure test_invalid() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 'foo', MYSQL_ERRNO = 'bar'; +end $$ +ERROR 42000: Duplicate condition information item 'MYSQL_ERRNO' +create procedure test_signal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET +CLASS_ORIGIN = 'foo', +SUBCLASS_ORIGIN = 'foo', +CONSTRAINT_CATALOG = 'foo', +CONSTRAINT_SCHEMA = 'foo', +CONSTRAINT_NAME = 'foo', +CATALOG_NAME = 'foo', +SCHEMA_NAME = 'foo', +TABLE_NAME = 'foo', +COLUMN_NAME = 'foo', +CURSOR_NAME = 'foo', +MESSAGE_TEXT = 'foo', +MYSQL_ERRNO = 'foo'; +end $$ +drop procedure test_signal_syntax $$ +SIGNAL SQLSTATE '00000' $$ +ERROR 42000: Bad SQLSTATE: '00000' +SIGNAL SQLSTATE '00001' $$ +ERROR 42000: Bad SQLSTATE: '00001' +create procedure test_invalid() +begin +SIGNAL SQLSTATE '00000'; +end $$ +ERROR 42000: Bad SQLSTATE: '00000' +create procedure test_invalid() +begin +SIGNAL SQLSTATE '00001'; +end $$ +ERROR 42000: Bad SQLSTATE: '00001' +# +# Test conditions information that SIGNAL can not set +# +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET bla_bla = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'bla_bla = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET CONDITION_IDENTIFIER = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CONDITION_IDENTIFIER = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET CONDITION_NUMBER = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CONDITION_NUMBER = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET CONNECTION_NAME = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CONNECTION_NAME = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET MESSAGE_LENGTH = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'MESSAGE_LENGTH = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET MESSAGE_OCTET_LENGTH = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'MESSAGE_OCTET_LENGTH = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET PARAMETER_MODE = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'PARAMETER_MODE = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET PARAMETER_NAME = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'PARAMETER_NAME = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET PARAMETER_ORDINAL_POSITION = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'PARAMETER_ORDINAL_POSITION = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET RETURNED_SQLSTATE = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETURNED_SQLSTATE = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET ROUTINE_CATALOG = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ROUTINE_CATALOG = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET ROUTINE_NAME = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ROUTINE_NAME = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET ROUTINE_SCHEMA = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ROUTINE_SCHEMA = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET SERVER_NAME = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SERVER_NAME = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET SPECIFIC_NAME = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SPECIFIC_NAME = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET TRIGGER_CATALOG = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TRIGGER_CATALOG = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET TRIGGER_NAME = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TRIGGER_NAME = 'foo'; +end' at line 3 +create procedure test_invalid() +begin +SIGNAL SQLSTATE '12345' SET TRIGGER_SCHEMA = 'foo'; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TRIGGER_SCHEMA = 'foo'; +end' at line 3 +# +# Test the RESIGNAL syntax +# +drop procedure if exists test_invalid; +drop procedure if exists test_resignal_syntax; +create procedure test_invalid() +begin +RESIGNAL foo; +end $$ +ERROR 42000: Undefined CONDITION: foo +create procedure test_resignal_syntax() +begin +RESIGNAL; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_invalid() +begin +DECLARE foo CONDITION FOR 1234; +RESIGNAL foo; +end $$ +ERROR HY000: SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SQLSTATE '23000'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SQLSTATE VALUE '23000'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET CLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET CLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET SUBCLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET SUBCLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET CONSTRAINT_CATALOG = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET CONSTRAINT_CATALOG = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET CONSTRAINT_SCHEMA = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET CONSTRAINT_SCHEMA = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET CONSTRAINT_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET CONSTRAINT_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET CATALOG_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET CATALOG_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET SCHEMA_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET SCHEMA_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET TABLE_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET TABLE_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET COLUMN_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET COLUMN_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET CURSOR_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET CURSOR_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET MESSAGE_TEXT = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET MESSAGE_TEXT = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +RESIGNAL SET MYSQL_ERRNO = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET MYSQL_ERRNO = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_invalid() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET CLASS_ORIGIN = 'foo', CLASS_ORIGIN = 'bar'; +end $$ +ERROR 42000: Duplicate condition information item 'CLASS_ORIGIN' +create procedure test_invalid() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET MESSAGE_TEXT = 'foo', MESSAGE_TEXT = 'bar'; +end $$ +ERROR 42000: Duplicate condition information item 'MESSAGE_TEXT' +create procedure test_invalid() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET MYSQL_ERRNO = 'foo', MYSQL_ERRNO = 'bar'; +end $$ +ERROR 42000: Duplicate condition information item 'MYSQL_ERRNO' +create procedure test_resignal_syntax() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +RESIGNAL foo SET +CLASS_ORIGIN = 'foo', +SUBCLASS_ORIGIN = 'foo', +CONSTRAINT_CATALOG = 'foo', +CONSTRAINT_SCHEMA = 'foo', +CONSTRAINT_NAME = 'foo', +CATALOG_NAME = 'foo', +SCHEMA_NAME = 'foo', +TABLE_NAME = 'foo', +COLUMN_NAME = 'foo', +CURSOR_NAME = 'foo', +MESSAGE_TEXT = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ +create procedure test_invalid() +begin +RESIGNAL SQLSTATE '00000'; +end $$ +ERROR 42000: Bad SQLSTATE: '00000' +create procedure test_invalid() +begin +RESIGNAL SQLSTATE '00001'; +end $$ +ERROR 42000: Bad SQLSTATE: '00001' +# +# PART 2: non preparable statements +# +prepare stmt from 'SIGNAL SQLSTATE \'23000\''; +ERROR HY000: This command is not supported in the prepared statement protocol yet +prepare stmt from 'RESIGNAL SQLSTATE \'23000\''; +ERROR HY000: This command is not supported in the prepared statement protocol yet +# +# PART 3: runtime execution +# +drop procedure if exists test_signal; +drop procedure if exists test_resignal; +drop table if exists t_warn; +drop table if exists t_cursor; +create table t_warn(a integer(2)); +create table t_cursor(a integer); +# +# SIGNAL can also appear in a query +# +SIGNAL foo; +ERROR 42000: Undefined CONDITION: foo +SIGNAL SQLSTATE '01000'; +Warnings: +Warning 1640 Unhandled user-defined warning condition +SIGNAL SQLSTATE '02000'; +ERROR 02000: Unhandled user-defined not found condition +SIGNAL SQLSTATE '23000'; +ERROR 23000: Unhandled user-defined exception condition +SIGNAL SQLSTATE VALUE '23000'; +ERROR 23000: Unhandled user-defined exception condition +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 65536; +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '65536' +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 99999; +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '99999' +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 4294967295; +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '4294967295' +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 0; +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '0' +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = -1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1' at line 1 +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 65535; +ERROR HY000: Unhandled user-defined exception condition +# +# RESIGNAL can also appear in a query +# +RESIGNAL; +ERROR 0K000: RESIGNAL when handler not active +RESIGNAL foo; +ERROR 42000: Undefined CONDITION: foo +RESIGNAL SQLSTATE '12345'; +ERROR 0K000: RESIGNAL when handler not active +RESIGNAL SQLSTATE VALUE '12345'; +ERROR 0K000: RESIGNAL when handler not active +# +# Different kind of SIGNAL conditions +# +create procedure test_signal() +begin +# max range +DECLARE foo CONDITION FOR SQLSTATE 'AABBB'; +SIGNAL foo SET MYSQL_ERRNO = 65535; +end $$ +call test_signal() $$ +ERROR AABBB: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# max range +DECLARE foo CONDITION FOR SQLSTATE 'AABBB'; +SIGNAL foo SET MYSQL_ERRNO = 65536; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '65536' +drop procedure test_signal $$ +create procedure test_signal() +begin +# Error +DECLARE foo CONDITION FOR SQLSTATE '99999'; +SIGNAL foo SET MYSQL_ERRNO = 9999; +end $$ +call test_signal() $$ +ERROR 99999: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# warning +DECLARE too_few_records CONDITION FOR SQLSTATE '01000'; +SIGNAL too_few_records SET MYSQL_ERRNO = 1261; +end $$ +call test_signal() $$ +Warnings: +Warning 1261 Unhandled user-defined warning condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Not found +DECLARE sp_fetch_no_data CONDITION FOR SQLSTATE '02000'; +SIGNAL sp_fetch_no_data SET MYSQL_ERRNO = 1329; +end $$ +call test_signal() $$ +ERROR 02000: Unhandled user-defined not found condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Error +DECLARE sp_cursor_already_open CONDITION FOR SQLSTATE '24000'; +SIGNAL sp_cursor_already_open SET MYSQL_ERRNO = 1325; +end $$ +call test_signal() $$ +ERROR 24000: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Severe error +DECLARE lock_deadlock CONDITION FOR SQLSTATE '40001'; +SIGNAL lock_deadlock SET MYSQL_ERRNO = 1213; +end $$ +call test_signal() $$ +ERROR 40001: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Unknown -> error +DECLARE foo CONDITION FOR SQLSTATE "99999"; +SIGNAL foo; +end $$ +call test_signal() $$ +ERROR 99999: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# warning, no subclass +DECLARE warn CONDITION FOR SQLSTATE "01000"; +SIGNAL warn; +end $$ +call test_signal() $$ +Warnings: +Warning 1640 Unhandled user-defined warning condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# warning, with subclass +DECLARE warn CONDITION FOR SQLSTATE "01123"; +SIGNAL warn; +end $$ +call test_signal() $$ +Warnings: +Warning 1640 Unhandled user-defined warning condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Not found, no subclass +DECLARE not_found CONDITION FOR SQLSTATE "02000"; +SIGNAL not_found; +end $$ +call test_signal() $$ +ERROR 02000: Unhandled user-defined not found condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Not found, with subclass +DECLARE not_found CONDITION FOR SQLSTATE "02XXX"; +SIGNAL not_found; +end $$ +call test_signal() $$ +ERROR 02XXX: Unhandled user-defined not found condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Error, no subclass +DECLARE error CONDITION FOR SQLSTATE "12000"; +SIGNAL error; +end $$ +call test_signal() $$ +ERROR 12000: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Error, with subclass +DECLARE error CONDITION FOR SQLSTATE "12ABC"; +SIGNAL error; +end $$ +call test_signal() $$ +ERROR 12ABC: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Severe error, no subclass +DECLARE error CONDITION FOR SQLSTATE "40000"; +SIGNAL error; +end $$ +call test_signal() $$ +ERROR 40000: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +# Severe error, with subclass +DECLARE error CONDITION FOR SQLSTATE "40001"; +SIGNAL error; +end $$ +call test_signal() $$ +ERROR 40001: Unhandled user-defined exception condition +drop procedure test_signal $$ +# +# Test the scope of condition +# +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '99999'; +begin +DECLARE foo CONDITION FOR 8888; +end; +SIGNAL foo SET MYSQL_ERRNO=9999; /* outer */ +end $$ +call test_signal() $$ +ERROR 99999: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR 9999; +begin +DECLARE foo CONDITION FOR SQLSTATE '88888'; +SIGNAL foo SET MYSQL_ERRNO=8888; /* inner */ +end; +end $$ +call test_signal() $$ +ERROR 88888: Unhandled user-defined exception condition +drop procedure test_signal $$ +# +# Test SET MYSQL_ERRNO +# +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '99999'; +SIGNAL foo SET MYSQL_ERRNO = 1111; +end $$ +call test_signal() $$ +ERROR 99999: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01000"; +SIGNAL warn SET MYSQL_ERRNO = 1111; +end $$ +call test_signal() $$ +Warnings: +Warning 1111 Unhandled user-defined warning condition +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02000"; +SIGNAL not_found SET MYSQL_ERRNO = 1111; +end $$ +call test_signal() $$ +ERROR 02000: Unhandled user-defined not found condition +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE "55000"; +SIGNAL error SET MYSQL_ERRNO = 1111; +end $$ +call test_signal() $$ +ERROR 55000: Unhandled user-defined exception condition +drop procedure test_signal $$ +# +# Test SET MESSAGE_TEXT +# +SIGNAL SQLSTATE '77777' SET MESSAGE_TEXT='' $$ +ERROR 77777: +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '77777'; +SIGNAL foo SET +MESSAGE_TEXT = "", +MYSQL_ERRNO=5678; +end $$ +call test_signal() $$ +ERROR 77777: +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '99999'; +SIGNAL foo SET +MESSAGE_TEXT = "Something bad happened", +MYSQL_ERRNO=9999; +end $$ +call test_signal() $$ +ERROR 99999: Something bad happened +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01000"; +SIGNAL warn SET MESSAGE_TEXT = "Something bad happened"; +end $$ +call test_signal() $$ +Warnings: +Warning 1640 Something bad happened +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02000"; +SIGNAL not_found SET MESSAGE_TEXT = "Something bad happened"; +end $$ +call test_signal() $$ +ERROR 02000: Something bad happened +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE "55000"; +SIGNAL error SET MESSAGE_TEXT = "Something bad happened"; +end $$ +call test_signal() $$ +ERROR 55000: Something bad happened +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE something CONDITION FOR SQLSTATE "01000"; +SIGNAL something SET MESSAGE_TEXT = _utf8 "This is a UTF8 text"; +end $$ +call test_signal() $$ +Warnings: +Warning 1640 This is a UTF8 text +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE something CONDITION FOR SQLSTATE "01000"; +SIGNAL something SET MESSAGE_TEXT = ""; +end $$ +call test_signal() $$ +Warnings: +Warning 1640 +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01111"; +SIGNAL warn SET MESSAGE_TEXT = "á a"; +end $$ +call test_signal() $$ +Warnings: +Warning 1640 á a +show warnings $$ +Level Code Message +Warning 1640 á a +drop procedure test_signal $$ +# +# Test SET complex expressions +# +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +MYSQL_ERRNO = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +CLASS_ORIGIN = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'CLASS_ORIGIN' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +SUBCLASS_ORIGIN = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'SUBCLASS_ORIGIN' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +CONSTRAINT_CATALOG = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'CONSTRAINT_CATALOG' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +CONSTRAINT_SCHEMA = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'CONSTRAINT_SCHEMA' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +CONSTRAINT_NAME = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'CONSTRAINT_NAME' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +CATALOG_NAME = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'CATALOG_NAME' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +SCHEMA_NAME = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'SCHEMA_NAME' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +TABLE_NAME = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'TABLE_NAME' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +COLUMN_NAME = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'COLUMN_NAME' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +CURSOR_NAME = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'CURSOR_NAME' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE '99999'; +SIGNAL error SET +MESSAGE_TEXT = NULL; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'MESSAGE_TEXT' can't be set to the value of 'NULL' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE something CONDITION FOR SQLSTATE '99999'; +DECLARE message_text VARCHAR(64) DEFAULT "Local string variable"; +DECLARE sqlcode INTEGER DEFAULT 1234; +SIGNAL something SET +MESSAGE_TEXT = message_text, +MYSQL_ERRNO = sqlcode; +end $$ +call test_signal() $$ +ERROR 99999: Local string variable +drop procedure test_signal $$ +create procedure test_signal(message_text VARCHAR(64), sqlcode INTEGER) +begin +DECLARE something CONDITION FOR SQLSTATE "12345"; +SIGNAL something SET +MESSAGE_TEXT = message_text, +MYSQL_ERRNO = sqlcode; +end $$ +call test_signal("Parameter string", NULL) $$ +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of 'NULL' +call test_signal(NULL, 1234) $$ +ERROR 42000: Variable 'MESSAGE_TEXT' can't be set to the value of 'NULL' +call test_signal("Parameter string", 5678) $$ +ERROR 12345: Parameter string +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE something CONDITION FOR SQLSTATE "AABBB"; +SIGNAL something SET +MESSAGE_TEXT = @message_text, +MYSQL_ERRNO = @sqlcode; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'MESSAGE_TEXT' can't be set to the value of 'NULL' +set @sqlcode= 12 $$ +call test_signal() $$ +ERROR 42000: Variable 'MESSAGE_TEXT' can't be set to the value of 'NULL' +set @message_text= "User variable" $$ +call test_signal() $$ +ERROR AABBB: User variable +drop procedure test_signal $$ +create procedure test_invalid() +begin +DECLARE something CONDITION FOR SQLSTATE "AABBB"; +SIGNAL something SET +MESSAGE_TEXT = @message_text := 'illegal', +MYSQL_ERRNO = @sqlcode := 1234; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' +MYSQL_ERRNO = @sqlcode := 1234; +end' at line 5 +create procedure test_signal() +begin +DECLARE aaa VARCHAR(64); +DECLARE bbb VARCHAR(64); +DECLARE ccc VARCHAR(64); +DECLARE ddd VARCHAR(64); +DECLARE eee VARCHAR(64); +DECLARE fff VARCHAR(64); +DECLARE ggg VARCHAR(64); +DECLARE hhh VARCHAR(64); +DECLARE iii VARCHAR(64); +DECLARE jjj VARCHAR(64); +DECLARE kkk VARCHAR(64); +DECLARE warn CONDITION FOR SQLSTATE "01234"; +set aaa= repeat("A", 64); +set bbb= repeat("B", 64); +set ccc= repeat("C", 64); +set ddd= repeat("D", 64); +set eee= repeat("E", 64); +set fff= repeat("F", 64); +set ggg= repeat("G", 64); +set hhh= repeat("H", 64); +set iii= repeat("I", 64); +set jjj= repeat("J", 64); +set kkk= repeat("K", 64); +SIGNAL warn SET +CLASS_ORIGIN = aaa, +SUBCLASS_ORIGIN = bbb, +CONSTRAINT_CATALOG = ccc, +CONSTRAINT_SCHEMA = ddd, +CONSTRAINT_NAME = eee, +CATALOG_NAME = fff, +SCHEMA_NAME = ggg, +TABLE_NAME = hhh, +COLUMN_NAME = iii, +CURSOR_NAME = jjj, +MESSAGE_TEXT = kkk, +MYSQL_ERRNO = 65535; +end $$ +call test_signal() $$ +Warnings: +Warning 65535 KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01234"; +SIGNAL warn SET +MYSQL_ERRNO = 999999999999999999999999999999999999999999999999999; +end $$ +call test_signal() $$ +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of '999999999999999999999999999999999999999999999999999' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE aaax VARCHAR(65); +DECLARE bbbx VARCHAR(65); +DECLARE cccx VARCHAR(65); +DECLARE dddx VARCHAR(65); +DECLARE eeex VARCHAR(65); +DECLARE fffx VARCHAR(65); +DECLARE gggx VARCHAR(65); +DECLARE hhhx VARCHAR(65); +DECLARE iiix VARCHAR(65); +DECLARE jjjx VARCHAR(65); +DECLARE kkkx VARCHAR(65); +DECLARE lllx VARCHAR(129); +DECLARE warn CONDITION FOR SQLSTATE "01234"; +set aaax= concat(repeat("A", 64), "X"); +set bbbx= concat(repeat("B", 64), "X"); +set cccx= concat(repeat("C", 64), "X"); +set dddx= concat(repeat("D", 64), "X"); +set eeex= concat(repeat("E", 64), "X"); +set fffx= concat(repeat("F", 64), "X"); +set gggx= concat(repeat("G", 64), "X"); +set hhhx= concat(repeat("H", 64), "X"); +set iiix= concat(repeat("I", 64), "X"); +set jjjx= concat(repeat("J", 64), "X"); +set kkkx= concat(repeat("K", 64), "X"); +set lllx= concat(repeat("1", 100), +repeat("2", 20), +repeat("8", 8), +"X"); +SIGNAL warn SET +CLASS_ORIGIN = aaax, +SUBCLASS_ORIGIN = bbbx, +CONSTRAINT_CATALOG = cccx, +CONSTRAINT_SCHEMA = dddx, +CONSTRAINT_NAME = eeex, +CATALOG_NAME = fffx, +SCHEMA_NAME = gggx, +TABLE_NAME = hhhx, +COLUMN_NAME = iiix, +CURSOR_NAME = jjjx, +MESSAGE_TEXT = lllx, +MYSQL_ERRNO = 10000; +end $$ +call test_signal() $$ +Warnings: +Warning 1645 Data truncated for condition item 'CLASS_ORIGIN' +Warning 1645 Data truncated for condition item 'SUBCLASS_ORIGIN' +Warning 1645 Data truncated for condition item 'CONSTRAINT_CATALOG' +Warning 1645 Data truncated for condition item 'CONSTRAINT_SCHEMA' +Warning 1645 Data truncated for condition item 'CONSTRAINT_NAME' +Warning 1645 Data truncated for condition item 'CATALOG_NAME' +Warning 1645 Data truncated for condition item 'SCHEMA_NAME' +Warning 1645 Data truncated for condition item 'TABLE_NAME' +Warning 1645 Data truncated for condition item 'COLUMN_NAME' +Warning 1645 Data truncated for condition item 'CURSOR_NAME' +Warning 1645 Data truncated for condition item 'MESSAGE_TEXT' +Warning 10000 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222288888888 +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01234"; +DECLARE CONTINUE HANDLER for SQLSTATE "01234" + begin +select "Caught by SQLSTATE"; +end; +SIGNAL warn SET +MESSAGE_TEXT = "Raising a warning", +MYSQL_ERRNO = 1012; +end $$ +call test_signal() $$ +Caught by SQLSTATE +Caught by SQLSTATE +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01234"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "Caught by number"; +end; +SIGNAL warn SET +MESSAGE_TEXT = "Raising a warning", +MYSQL_ERRNO = 1012; +end $$ +call test_signal() $$ +Caught by number +Caught by number +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01234"; +DECLARE CONTINUE HANDLER for SQLWARNING +begin +select "Caught by SQLWARNING"; +end; +SIGNAL warn SET +MESSAGE_TEXT = "Raising a warning", +MYSQL_ERRNO = 1012; +end $$ +call test_signal() $$ +Caught by SQLWARNING +Caught by SQLWARNING +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; +DECLARE CONTINUE HANDLER for SQLSTATE "02ABC" + begin +select "Caught by SQLSTATE"; +end; +SIGNAL not_found SET +MESSAGE_TEXT = "Raising a not found", +MYSQL_ERRNO = 1012; +end $$ +call test_signal() $$ +Caught by SQLSTATE +Caught by SQLSTATE +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "Caught by number"; +end; +SIGNAL not_found SET +MESSAGE_TEXT = "Raising a not found", +MYSQL_ERRNO = 1012; +end $$ +call test_signal() $$ +Caught by number +Caught by number +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; +DECLARE CONTINUE HANDLER for NOT FOUND +begin +select "Caught by NOT FOUND"; +end; +SIGNAL not_found SET +MESSAGE_TEXT = "Raising a not found", +MYSQL_ERRNO = 1012; +end $$ +call test_signal() $$ +Caught by NOT FOUND +Caught by NOT FOUND +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE "55555"; +DECLARE CONTINUE HANDLER for SQLSTATE "55555" + begin +select "Caught by SQLSTATE"; +end; +SIGNAL error SET +MESSAGE_TEXT = "Raising an error", +MYSQL_ERRNO = 1012; +end $$ +call test_signal() $$ +Caught by SQLSTATE +Caught by SQLSTATE +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE "55555"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "Caught by number"; +end; +SIGNAL error SET +MESSAGE_TEXT = "Raising an error", +MYSQL_ERRNO = 1012; +end $$ +call test_signal() $$ +Caught by number +Caught by number +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE error CONDITION FOR SQLSTATE "55555"; +DECLARE CONTINUE HANDLER for SQLEXCEPTION +begin +select "Caught by SQLEXCEPTION"; +end; +SIGNAL error SET +MESSAGE_TEXT = "Raising an error", +MYSQL_ERRNO = 1012; +end $$ +call test_signal() $$ +Caught by SQLEXCEPTION +Caught by SQLEXCEPTION +drop procedure test_signal $$ +# +# Test where SIGNAL can be used +# +create function test_signal_func() returns integer +begin +DECLARE warn CONDITION FOR SQLSTATE "01XXX"; +SIGNAL warn SET +MESSAGE_TEXT = "This function SIGNAL a warning", +MYSQL_ERRNO = 1012; +return 5; +end $$ +select test_signal_func() $$ +test_signal_func() +5 +Warnings: +Warning 1012 This function SIGNAL a warning +drop function test_signal_func $$ +create function test_signal_func() returns integer +begin +DECLARE not_found CONDITION FOR SQLSTATE "02XXX"; +SIGNAL not_found SET +MESSAGE_TEXT = "This function SIGNAL not found", +MYSQL_ERRNO = 1012; +return 5; +end $$ +select test_signal_func() $$ +ERROR 02XXX: This function SIGNAL not found +drop function test_signal_func $$ +create function test_signal_func() returns integer +begin +DECLARE error CONDITION FOR SQLSTATE "50000"; +SIGNAL error SET +MESSAGE_TEXT = "This function SIGNAL an error", +MYSQL_ERRNO = 1012; +return 5; +end $$ +select test_signal_func() $$ +ERROR 50000: This function SIGNAL an error +drop function test_signal_func $$ +drop table if exists t1 $$ +create table t1 (a integer) $$ +create trigger t1_ai after insert on t1 for each row +begin +DECLARE msg VARCHAR(128); +DECLARE warn CONDITION FOR SQLSTATE "01XXX"; +set msg= concat("This trigger SIGNAL a warning, a=", NEW.a); +SIGNAL warn SET +MESSAGE_TEXT = msg, +MYSQL_ERRNO = 1012; +end $$ +insert into t1 values (1), (2) $$ +Warnings: +Warning 1012 This trigger SIGNAL a warning, a=1 +Warning 1012 This trigger SIGNAL a warning, a=2 +drop trigger t1_ai $$ +create trigger t1_ai after insert on t1 for each row +begin +DECLARE msg VARCHAR(128); +DECLARE not_found CONDITION FOR SQLSTATE "02XXX"; +set msg= concat("This trigger SIGNAL a not found, a=", NEW.a); +SIGNAL not_found SET +MESSAGE_TEXT = msg, +MYSQL_ERRNO = 1012; +end $$ +insert into t1 values (3), (4) $$ +ERROR 02XXX: This trigger SIGNAL a not found, a=3 +drop trigger t1_ai $$ +create trigger t1_ai after insert on t1 for each row +begin +DECLARE msg VARCHAR(128); +DECLARE error CONDITION FOR SQLSTATE "03XXX"; +set msg= concat("This trigger SIGNAL an error, a=", NEW.a); +SIGNAL error SET +MESSAGE_TEXT = msg, +MYSQL_ERRNO = 1012; +end $$ +insert into t1 values (5), (6) $$ +ERROR 03XXX: This trigger SIGNAL an error, a=5 +drop table t1 $$ +create table t1 (errno integer, msg varchar(128)) $$ +create trigger t1_ai after insert on t1 for each row +begin +DECLARE warn CONDITION FOR SQLSTATE "01XXX"; +SIGNAL warn SET +MESSAGE_TEXT = NEW.msg, +MYSQL_ERRNO = NEW.errno; +end $$ +insert into t1 set errno=1012, msg='Warning message 1 in trigger' $$ +Warnings: +Warning 1012 Warning message 1 in trigger +insert into t1 set errno=1013, msg='Warning message 2 in trigger' $$ +Warnings: +Warning 1013 Warning message 2 in trigger +drop table t1 $$ +drop table if exists t1 $$ +drop procedure if exists p1 $$ +drop function if exists f1 $$ +create table t1 (s1 int) $$ +insert into t1 values (1) $$ +create procedure p1() +begin +declare a int; +declare c cursor for select f1() from t1; +declare continue handler for sqlstate '03000' + select "caught 03000"; +declare continue handler for 1326 +select "caught cursor is not open"; +select "Before open"; +open c; +select "Before fetch"; +fetch c into a; +select "Before close"; +close c; +end $$ +create function f1() returns int +begin +signal sqlstate '03000'; +return 5; +end $$ +drop table t1 $$ +drop procedure p1 $$ +drop function f1 $$ +# +# Test the RESIGNAL runtime +# +create procedure test_resignal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01234"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL; +select "after RESIGNAL"; +end; +SIGNAL warn SET +MESSAGE_TEXT = "Raising a warning", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Warning 1012 Raising a warning +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02222"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL; +select "after RESIGNAL"; +end; +SIGNAL not_found SET +MESSAGE_TEXT = "Raising a not found", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02222: Raising a not found +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE error CONDITION FOR SQLSTATE "55555"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL; +select "after RESIGNAL"; +end; +SIGNAL error SET +MESSAGE_TEXT = "Raising an error", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 55555: Raising an error +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlwarning +begin +select "before RESIGNAL"; +RESIGNAL; +select "after RESIGNAL"; +end; +insert into t_warn set a= 9999999999999999; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE x integer; +DECLARE c cursor for select * from t_cursor; +DECLARE CONTINUE HANDLER for not found +begin +select "before RESIGNAL"; +RESIGNAL; +select "after RESIGNAL"; +end; +open c; +fetch c into x; +close c; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02000: No data - zero rows fetched, selected, or processed +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlexception +begin +select "before RESIGNAL"; +RESIGNAL; +select "after RESIGNAL"; +end; +drop table no_such_table; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 42S02: Unknown table 'no_such_table' +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01234"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SET +MESSAGE_TEXT = "RESIGNAL of a warning", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL warn SET +MESSAGE_TEXT = "Raising a warning", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Warning 5555 RESIGNAL of a warning +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02111"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SET +MESSAGE_TEXT = "RESIGNAL of a not found", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL not_found SET +MESSAGE_TEXT = "Raising a not found", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02111: RESIGNAL of a not found +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE error CONDITION FOR SQLSTATE "33333"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SET +MESSAGE_TEXT = "RESIGNAL of an error", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL error SET +MESSAGE_TEXT = "Raising an error", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 33333: RESIGNAL of an error +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlwarning +begin +select "before RESIGNAL"; +RESIGNAL SET +MESSAGE_TEXT = "RESIGNAL of a warning", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +insert into t_warn set a= 9999999999999999; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Warning 5555 RESIGNAL of a warning +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE x integer; +DECLARE c cursor for select * from t_cursor; +DECLARE CONTINUE HANDLER for not found +begin +select "before RESIGNAL"; +RESIGNAL SET +MESSAGE_TEXT = "RESIGNAL of not found", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +open c; +fetch c into x; +close c; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02000: RESIGNAL of not found +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlexception +begin +select "before RESIGNAL"; +RESIGNAL SET +MESSAGE_TEXT = "RESIGNAL of an error", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +drop table no_such_table; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 42S02: RESIGNAL of an error +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01111"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "01222" SET +MESSAGE_TEXT = "RESIGNAL to warning", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL warn SET +MESSAGE_TEXT = "Raising a warning", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Warning 1012 Raising a warning +Warning 5555 RESIGNAL to warning +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01111"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "02222" SET +MESSAGE_TEXT = "RESIGNAL to not found", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL warn SET +MESSAGE_TEXT = "Raising a warning", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02222: RESIGNAL to not found +show warnings $$ +Level Code Message +Warning 1012 Raising a warning +Error 5555 RESIGNAL to not found +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE warn CONDITION FOR SQLSTATE "01111"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "33333" SET +MESSAGE_TEXT = "RESIGNAL to error", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL warn SET +MESSAGE_TEXT = "Raising a warning", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 33333: RESIGNAL to error +show warnings $$ +Level Code Message +Warning 1012 Raising a warning +Error 5555 RESIGNAL to error +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "01222" SET +MESSAGE_TEXT = "RESIGNAL to warning", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL not_found SET +MESSAGE_TEXT = "Raising a not found", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Error 1012 Raising a not found +Warning 5555 RESIGNAL to warning +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "02222" SET +MESSAGE_TEXT = "RESIGNAL to not found", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL not_found SET +MESSAGE_TEXT = "Raising a not found", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02222: RESIGNAL to not found +show warnings $$ +Level Code Message +Error 1012 Raising a not found +Error 5555 RESIGNAL to not found +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "33333" SET +MESSAGE_TEXT = "RESIGNAL to error", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL not_found SET +MESSAGE_TEXT = "Raising a not found", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 33333: RESIGNAL to error +show warnings $$ +Level Code Message +Error 1012 Raising a not found +Error 5555 RESIGNAL to error +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE error CONDITION FOR SQLSTATE "AAAAA"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "01222" SET +MESSAGE_TEXT = "RESIGNAL to warning", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL error SET +MESSAGE_TEXT = "Raising an error", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Error 1012 Raising an error +Warning 5555 RESIGNAL to warning +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE error CONDITION FOR SQLSTATE "AAAAA"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "02222" SET +MESSAGE_TEXT = "RESIGNAL to not found", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL error SET +MESSAGE_TEXT = "Raising an error", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02222: RESIGNAL to not found +show warnings $$ +Level Code Message +Error 1012 Raising an error +Error 5555 RESIGNAL to not found +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE error CONDITION FOR SQLSTATE "AAAAA"; +DECLARE CONTINUE HANDLER for 1012 +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "33333" SET +MESSAGE_TEXT = "RESIGNAL to error", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +SIGNAL error SET +MESSAGE_TEXT = "Raising an error", +MYSQL_ERRNO = 1012; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 33333: RESIGNAL to error +show warnings $$ +Level Code Message +Error 1012 Raising an error +Error 5555 RESIGNAL to error +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlwarning +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "01111" SET +MESSAGE_TEXT = "RESIGNAL to a warning", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +insert into t_warn set a= 9999999999999999; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +Warning 5555 RESIGNAL to a warning +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlwarning +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "02444" SET +MESSAGE_TEXT = "RESIGNAL to a not found", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +insert into t_warn set a= 9999999999999999; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02444: RESIGNAL to a not found +show warnings $$ +Level Code Message +Warning 1264 Out of range value for column 'a' at row 1 +Error 5555 RESIGNAL to a not found +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlwarning +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "44444" SET +MESSAGE_TEXT = "RESIGNAL to an error", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +insert into t_warn set a= 9999999999999999; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 44444: RESIGNAL to an error +show warnings $$ +Level Code Message +Warning 1264 Out of range value for column 'a' at row 1 +Error 5555 RESIGNAL to an error +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE x integer; +DECLARE c cursor for select * from t_cursor; +DECLARE CONTINUE HANDLER for not found +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "01111" SET +MESSAGE_TEXT = "RESIGNAL to a warning", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +open c; +fetch c into x; +close c; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Error 1329 No data - zero rows fetched, selected, or processed +Warning 5555 RESIGNAL to a warning +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE x integer; +DECLARE c cursor for select * from t_cursor; +DECLARE CONTINUE HANDLER for not found +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "02444" SET +MESSAGE_TEXT = "RESIGNAL to a not found", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +open c; +fetch c into x; +close c; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02444: RESIGNAL to a not found +show warnings $$ +Level Code Message +Error 1329 No data - zero rows fetched, selected, or processed +Error 5555 RESIGNAL to a not found +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE x integer; +DECLARE c cursor for select * from t_cursor; +DECLARE CONTINUE HANDLER for not found +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "44444" SET +MESSAGE_TEXT = "RESIGNAL to an error", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +open c; +fetch c into x; +close c; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 44444: RESIGNAL to an error +show warnings $$ +Level Code Message +Error 1329 No data - zero rows fetched, selected, or processed +Error 5555 RESIGNAL to an error +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlexception +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "01111" SET +MESSAGE_TEXT = "RESIGNAL to a warning", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +drop table no_such_table; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +after RESIGNAL +after RESIGNAL +Warnings: +Error 1051 Unknown table 'no_such_table' +Warning 5555 RESIGNAL to a warning +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlexception +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "02444" SET +MESSAGE_TEXT = "RESIGNAL to a not found", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +drop table no_such_table; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 02444: RESIGNAL to a not found +show warnings $$ +Level Code Message +Error 1051 Unknown table 'no_such_table' +Error 5555 RESIGNAL to a not found +drop procedure test_resignal $$ +create procedure test_resignal() +begin +DECLARE CONTINUE HANDLER for sqlexception +begin +select "before RESIGNAL"; +RESIGNAL SQLSTATE "44444" SET +MESSAGE_TEXT = "RESIGNAL to an error", +MYSQL_ERRNO = 5555 ; +select "after RESIGNAL"; +end; +drop table no_such_table; +end $$ +call test_resignal() $$ +before RESIGNAL +before RESIGNAL +ERROR 44444: RESIGNAL to an error +show warnings $$ +Level Code Message +Error 1051 Unknown table 'no_such_table' +Error 5555 RESIGNAL to an error +drop procedure test_resignal $$ +# +# More complex cases +# +drop procedure if exists peter_p1 $$ +drop procedure if exists peter_p2 $$ +CREATE PROCEDURE peter_p1 () +BEGIN +DECLARE x CONDITION FOR 1231; +DECLARE EXIT HANDLER FOR x +BEGIN +SELECT '2'; +RESIGNAL SET MYSQL_ERRNO = 9999; +END; +BEGIN +DECLARE EXIT HANDLER FOR x +BEGIN +SELECT '1'; +RESIGNAL SET SCHEMA_NAME = 'test'; +END; +SET @@sql_mode=NULL; +END; +END +$$ +CREATE PROCEDURE peter_p2 () +BEGIN +DECLARE x CONDITION for 9999; +DECLARE EXIT HANDLER FOR x +BEGIN +SELECT '3'; +RESIGNAL SET MESSAGE_TEXT = 'Hi, I am a useless error message'; +END; +CALL peter_p1(); +END +$$ +CALL peter_p2() $$ +1 +1 +2 +2 +3 +3 +ERROR 42000: Hi, I am a useless error message +show warnings $$ +Level Code Message +Error 9999 Hi, I am a useless error message +drop procedure peter_p1 $$ +drop procedure peter_p2 $$ +CREATE PROCEDURE peter_p1 () +BEGIN +DECLARE x CONDITION FOR SQLSTATE '42000'; +DECLARE EXIT HANDLER FOR x +BEGIN +SELECT '2'; +RESIGNAL x SET MYSQL_ERRNO = 9999; +END; +BEGIN +DECLARE EXIT HANDLER FOR x +BEGIN +SELECT '1'; +RESIGNAL x SET +SCHEMA_NAME = 'test', +MYSQL_ERRNO= 1231; +END; +/* Raises ER_WRONG_VALUE_FOR_VAR : 1231, SQLSTATE 42000 */ +SET @@sql_mode=NULL; +END; +END +$$ +CREATE PROCEDURE peter_p2 () +BEGIN +DECLARE x CONDITION for SQLSTATE '42000'; +DECLARE EXIT HANDLER FOR x +BEGIN +SELECT '3'; +RESIGNAL x SET +MESSAGE_TEXT = 'Hi, I am a useless error message', +MYSQL_ERRNO = 9999; +END; +CALL peter_p1(); +END +$$ +CALL peter_p2() $$ +1 +1 +2 +2 +3 +3 +ERROR 42000: Hi, I am a useless error message +show warnings $$ +Level Code Message +Error 1231 Variable 'sql_mode' can't be set to the value of 'NULL' +Error 1231 Variable 'sql_mode' can't be set to the value of 'NULL' +Error 9999 Variable 'sql_mode' can't be set to the value of 'NULL' +Error 9999 Hi, I am a useless error message +drop procedure peter_p1 $$ +drop procedure peter_p2 $$ +drop procedure if exists peter_p3 $$ +Warnings: +Note 1305 PROCEDURE peter_p3 does not exist +create procedure peter_p3() +begin +declare continue handler for sqlexception +resignal sqlstate '99002' set mysql_errno = 2; +signal sqlstate '99001' set mysql_errno = 1, message_text = "Original"; +end $$ +call peter_p3() $$ +ERROR 99002: Original +show warnings $$ +Level Code Message +Error 1 Original +Error 2 Original +drop procedure peter_p3 $$ +drop table t_warn; +drop table t_cursor; +# +# Miscelaneous test cases +# +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 0x12; /* 18 */ +end $$ +call test_signal $$ +ERROR 12345: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 0b00010010; /* 18 */ +end $$ +call test_signal $$ +ERROR 12345: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = '65'; /* 65 */ +end $$ +call test_signal $$ +ERROR 12345: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 'A'; /* illegal */ +end $$ +call test_signal $$ +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of 'A' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = "65"; /* 65 */ +end $$ +call test_signal $$ +ERROR 12345: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = "A"; /* illegal */ +end $$ +call test_signal $$ +ERROR 42000: Variable 'MYSQL_ERRNO' can't be set to the value of 'A' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = `65`; /* illegal */ +end $$ +call test_signal $$ +ERROR 42S22: Unknown column '65' in 'field list' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = `A`; /* illegal */ +end $$ +call test_signal $$ +ERROR 42S22: Unknown column 'A' in 'field list' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 3.141592; /* 3 */ +end $$ +call test_signal $$ +ERROR 12345: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 1000, +MESSAGE_TEXT= 0x41; /* A */ +end $$ +call test_signal $$ +ERROR 12345: A +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 1000, +MESSAGE_TEXT= 0b01000001; /* A */ +end $$ +call test_signal $$ +ERROR 12345: A +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 1000, +MESSAGE_TEXT = "Hello"; +end $$ +call test_signal $$ +ERROR 12345: Hello +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 1000, +MESSAGE_TEXT = 'Hello'; +end $$ +call test_signal $$ +ERROR 12345: Hello +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 1000, +MESSAGE_TEXT = `Hello`; +end $$ +call test_signal $$ +ERROR 42S22: Unknown column 'Hello' in 'field list' +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo SET MYSQL_ERRNO = 1000, +MESSAGE_TEXT = 65.4321; +end $$ +call test_signal $$ +ERROR 12345: 65.4321 +drop procedure test_signal $$ +create procedure test_signal() +begin +DECLARE céèçà foo CONDITION FOR SQLSTATE '12345'; +SIGNAL céèçà SET MYSQL_ERRNO = 1000; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '©Ã¨Ã§Ã  foo CONDITION FOR SQLSTATE '12345'; +SIGNAL céèçà SET MYSQL_ERRNO = 1' at line 3 +create procedure test_signal() +begin +DECLARE "céèçà" CONDITION FOR SQLSTATE '12345'; +SIGNAL "céèçà" SET MYSQL_ERRNO = 1000; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"céèçà" CONDITION FOR SQLSTATE '12345'; +SIGNAL "céèçà" SET MYSQL_ERRNO =' at line 3 +create procedure test_signal() +begin +DECLARE 'céèçà' CONDITION FOR SQLSTATE '12345'; +SIGNAL 'céèçà' SET MYSQL_ERRNO = 1000; +end $$ +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''céèçà' CONDITION FOR SQLSTATE '12345'; +SIGNAL 'céèçà' SET MYSQL_ERRNO =' at line 3 +create procedure test_signal() +begin +DECLARE `céèçà` CONDITION FOR SQLSTATE '12345'; +SIGNAL `céèçà` SET MYSQL_ERRNO = 1000; +end $$ +call test_signal $$ +ERROR 12345: Unhandled user-defined exception condition +drop procedure test_signal $$ +create procedure test_signal() +begin +SIGNAL SQLSTATE '77777' SET MYSQL_ERRNO = 1000, MESSAGE_TEXT='ÃÂÃÅÄ'; +end $$ +drop procedure test_signal $$ diff --git a/mysql-test/r/signal_code.result b/mysql-test/r/signal_code.result new file mode 100644 index 00000000000..63db6656636 --- /dev/null +++ b/mysql-test/r/signal_code.result @@ -0,0 +1,35 @@ +use test; +drop procedure if exists signal_proc; +drop function if exists signal_func; +create procedure signal_proc() +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo; +SIGNAL foo SET MESSAGE_TEXT = "This is an error message"; +RESIGNAL foo; +RESIGNAL foo SET MESSAGE_TEXT = "This is an error message"; +end $$ +create function signal_func() returns int +begin +DECLARE foo CONDITION FOR SQLSTATE '12345'; +SIGNAL foo; +SIGNAL foo SET MESSAGE_TEXT = "This is an error message"; +RESIGNAL foo; +RESIGNAL foo SET MESSAGE_TEXT = "This is an error message"; +return 0; +end $$ +show procedure code signal_proc; +Pos Instruction +0 stmt 136 "SIGNAL foo" +1 stmt 136 "SIGNAL foo SET MESSAGE_TEXT = "This i..." +2 stmt 137 "RESIGNAL foo" +3 stmt 137 "RESIGNAL foo SET MESSAGE_TEXT = "This..." +drop procedure signal_proc; +show function code signal_func; +Pos Instruction +0 stmt 136 "SIGNAL foo" +1 stmt 136 "SIGNAL foo SET MESSAGE_TEXT = "This i..." +2 stmt 137 "RESIGNAL foo" +3 stmt 137 "RESIGNAL foo SET MESSAGE_TEXT = "This..." +4 freturn 3 0 +drop function signal_func; diff --git a/mysql-test/r/signal_demo1.result b/mysql-test/r/signal_demo1.result new file mode 100644 index 00000000000..752f23a48d6 --- /dev/null +++ b/mysql-test/r/signal_demo1.result @@ -0,0 +1,270 @@ +drop database if exists demo; +create database demo; +use demo; +create table ab_physical_person ( +person_id integer, +first_name VARCHAR(50), +middle_initial CHAR, +last_name VARCHAR(50), +primary key (person_id)); +create table ab_moral_person ( +company_id integer, +name VARCHAR(100), +primary key (company_id)); +create table in_inventory ( +item_id integer, +descr VARCHAR(50), +stock integer, +primary key (item_id)); +create table po_order ( +po_id integer auto_increment, +cust_type char, /* arc relationship, see cust_id */ +cust_id integer, /* FK to ab_physical_person *OR* ab_moral_person */ +primary key (po_id)); +create table po_order_line ( +po_id integer, /* FK to po_order.po_id */ +line_no integer, +item_id integer, /* FK to in_inventory.item_id */ +qty integer); +# +# Schema integrity enforcement +# +create procedure check_pk_person(in person_type char, in id integer) +begin +declare x integer; +declare msg varchar(128); +/* +Test integrity constraints for an 'arc' relationship. +Based on 'person_type', 'id' points to either a +physical person, or a moral person. +*/ +case person_type +when 'P' then +begin +select count(person_id) from ab_physical_person +where ab_physical_person.person_id = id +into x; +if (x != 1) +then +set msg= concat('No such physical person, PK:', id); +SIGNAL SQLSTATE '45000' SET +MESSAGE_TEXT = msg, +MYSQL_ERRNO = 10000; +end if; +end; +when 'M' then +begin +select count(company_id) from ab_moral_person +where ab_moral_person.company_id = id +into x; +if (x != 1) +then +set msg= concat('No such moral person, PK:', id); +SIGNAL SQLSTATE '45000' SET +MESSAGE_TEXT = msg, +MYSQL_ERRNO = 10000; +end if; +end; +else +begin +set msg= concat('No such person type:', person_type); +SIGNAL SQLSTATE '45000' SET +MESSAGE_TEXT = msg, +MYSQL_ERRNO = 20000; +end; +end case; +end +$$ +create procedure check_pk_inventory(in id integer) +begin +declare x integer; +declare msg varchar(128); +select count(item_id) from in_inventory +where in_inventory.item_id = id +into x; +if (x != 1) +then +set msg= concat('Failed integrity constraint, table in_inventory, PK:', +id); +SIGNAL SQLSTATE '45000' SET +MESSAGE_TEXT = msg, +MYSQL_ERRNO = 10000; +end if; +end +$$ +create procedure check_pk_order(in id integer) +begin +declare x integer; +declare msg varchar(128); +select count(po_id) from po_order +where po_order.po_id = id +into x; +if (x != 1) +then +set msg= concat('Failed integrity constraint, table po_order, PK:', id); +SIGNAL SQLSTATE '45000' SET +MESSAGE_TEXT = msg, +MYSQL_ERRNO = 10000; +end if; +end +$$ +create trigger po_order_bi before insert on po_order +for each row +begin +call check_pk_person(NEW.cust_type, NEW.cust_id); +end +$$ +create trigger po_order_bu before update on po_order +for each row +begin +call check_pk_person(NEW.cust_type, NEW.cust_id); +end +$$ +create trigger po_order_line_bi before insert on po_order_line +for each row +begin +call check_pk_order(NEW.po_id); +call check_pk_inventory(NEW.item_id); +end +$$ +create trigger po_order_line_bu before update on po_order_line +for each row +begin +call check_pk_order(NEW.po_id); +call check_pk_inventory(NEW.item_id); +end +$$ +# +# Application helpers +# +create procedure po_create_order( +in p_cust_type char, +in p_cust_id integer, +out id integer) +begin +insert into po_order set cust_type = p_cust_type, cust_id = p_cust_id; +set id = last_insert_id(); +end +$$ +create procedure po_add_order_line( +in po integer, +in line integer, +in item integer, +in q integer) +begin +insert into po_order_line set +po_id = po, line_no = line, item_id = item, qty = q; +end +$$ +# +# Create sample data +# +insert into ab_physical_person values +( 1, "John", "A", "Doe"), +( 2, "Marry", "B", "Smith") +; +insert into ab_moral_person values +( 3, "ACME real estate, INC"), +( 4, "Local school") +; +insert into in_inventory values +( 100, "Table, dinner", 5), +( 101, "Chair", 20), +( 200, "Table, coffee", 3), +( 300, "School table", 25), +( 301, "School chairs", 50) +; +select * from ab_physical_person order by person_id; +person_id first_name middle_initial last_name +1 John A Doe +2 Marry B Smith +select * from ab_moral_person order by company_id; +company_id name +3 ACME real estate, INC +4 Local school +select * from in_inventory order by item_id; +item_id descr stock +100 Table, dinner 5 +101 Chair 20 +200 Table, coffee 3 +300 School table 25 +301 School chairs 50 +# +# Entering an order +# +set @my_po = 0; +/* John Doe wants 1 table and 4 chairs */ +call po_create_order("P", 1, @my_po); +call po_add_order_line (@my_po, 1, 100, 1); +call po_add_order_line (@my_po, 2, 101, 4); +/* Marry Smith wants a coffee table */ +call po_create_order("P", 2, @my_po); +call po_add_order_line (@my_po, 1, 200, 1); +# +# Entering bad data in an order +# +call po_add_order_line (@my_po, 1, 999, 1); +ERROR 45000: Failed integrity constraint, table in_inventory, PK:999 +# +# Entering bad data in an unknown order +# +call po_add_order_line (99, 1, 100, 1); +ERROR 45000: Failed integrity constraint, table po_order, PK:99 +# +# Entering an order for an unknown company +# +call po_create_order("M", 7, @my_po); +ERROR 45000: No such moral person, PK:7 +# +# Entering an order for an unknown person type +# +call po_create_order("X", 1, @my_po); +ERROR 45000: No such person type:X +/* The local school wants 10 class tables and 20 chairs */ +call po_create_order("M", 4, @my_po); +call po_add_order_line (@my_po, 1, 300, 10); +call po_add_order_line (@my_po, 2, 301, 20); +select * from po_order; +po_id cust_type cust_id +1 P 1 +2 P 2 +3 M 4 +select * from po_order_line; +po_id line_no item_id qty +1 1 100 1 +1 2 101 4 +2 1 200 1 +3 1 300 10 +3 2 301 20 +select po_id as "PO#", +( case cust_type +when "P" then concat (pp.first_name, +" ", +pp.middle_initial, +" ", +pp.last_name) +when "M" then mp.name +end ) as "Sold to" + from po_order po +left join ab_physical_person pp on po.cust_id = pp.person_id +left join ab_moral_person mp on po.cust_id = company_id +; +PO# Sold to +1 John A Doe +2 Marry B Smith +3 Local school +select po_id as "PO#", +ol.line_no as "Line", +ol.item_id as "Item", +inv.descr as "Description", +ol.qty as "Quantity" + from po_order_line ol, in_inventory inv +where inv.item_id = ol.item_id +order by ol.item_id, ol.line_no; +PO# Line Item Description Quantity +1 1 100 Table, dinner 1 +1 2 101 Chair 4 +2 1 200 Table, coffee 1 +3 1 300 School table 10 +3 2 301 School chairs 20 +drop database demo; diff --git a/mysql-test/r/signal_demo2.result b/mysql-test/r/signal_demo2.result new file mode 100644 index 00000000000..223030b0624 --- /dev/null +++ b/mysql-test/r/signal_demo2.result @@ -0,0 +1,197 @@ +drop database if exists demo; +create database demo; +use demo; +create procedure proc_top_a(p1 integer) +begin +## DECLARE CONTINUE HANDLER for SQLEXCEPTION, NOT FOUND +begin +end; +select "Starting ..."; +call proc_middle_a(p1); +select "The end"; +end +$$ +create procedure proc_middle_a(p1 integer) +begin +DECLARE l integer; +# without RESIGNAL: +# Should be: DECLARE EXIT HANDLER for SQLEXCEPTION, NOT FOUND +DECLARE EXIT HANDLER for 1 /* not sure how to handle exceptions */ +begin +select "Oops ... now what ?"; +end; +select "In prod_middle()"; +create temporary table t1(a integer, b integer); +select GET_LOCK("user_mutex", 10) into l; +insert into t1 set a = p1, b = p1; +call proc_bottom_a(p1); +select RELEASE_LOCK("user_mutex") into l; +drop temporary table t1; +end +$$ +create procedure proc_bottom_a(p1 integer) +begin +select "In proc_bottom()"; +if (p1 = 1) then +begin +select "Doing something that works ..."; +select * from t1; +end; +end if; +if (p1 = 2) then +begin +select "Doing something that fail (simulate an error) ..."; +drop table no_such_table; +end; +end if; +if (p1 = 3) then +begin +select "Doing something that *SHOULD* works ..."; +select * from t1; +end; +end if; +end +$$ +call proc_top_a(1); +Starting ... +Starting ... +In prod_middle() +In prod_middle() +In proc_bottom() +In proc_bottom() +Doing something that works ... +Doing something that works ... +a b +1 1 +The end +The end +call proc_top_a(2); +Starting ... +Starting ... +In prod_middle() +In prod_middle() +In proc_bottom() +In proc_bottom() +Doing something that fail (simulate an error) ... +Doing something that fail (simulate an error) ... +ERROR 42S02: Unknown table 'no_such_table' +call proc_top_a(3); +Starting ... +Starting ... +In prod_middle() +In prod_middle() +ERROR 42S01: Table 't1' already exists +call proc_top_a(1); +Starting ... +Starting ... +In prod_middle() +In prod_middle() +ERROR 42S01: Table 't1' already exists +drop temporary table if exists t1; +create procedure proc_top_b(p1 integer) +begin +select "Starting ..."; +call proc_middle_b(p1); +select "The end"; +end +$$ +create procedure proc_middle_b(p1 integer) +begin +DECLARE l integer; +DECLARE EXIT HANDLER for SQLEXCEPTION, NOT FOUND +begin +begin +DECLARE CONTINUE HANDLER for SQLEXCEPTION, NOT FOUND +begin +/* Ignore errors from the cleanup code */ +end; +select "Doing cleanup !"; +select RELEASE_LOCK("user_mutex") into l; +drop temporary table t1; +end; +RESIGNAL; +end; +select "In prod_middle()"; +create temporary table t1(a integer, b integer); +select GET_LOCK("user_mutex", 10) into l; +insert into t1 set a = p1, b = p1; +call proc_bottom_b(p1); +select RELEASE_LOCK("user_mutex") into l; +drop temporary table t1; +end +$$ +create procedure proc_bottom_b(p1 integer) +begin +select "In proc_bottom()"; +if (p1 = 1) then +begin +select "Doing something that works ..."; +select * from t1; +end; +end if; +if (p1 = 2) then +begin +select "Doing something that fail (simulate an error) ..."; +drop table no_such_table; +end; +end if; +if (p1 = 3) then +begin +select "Doing something that *SHOULD* works ..."; +select * from t1; +end; +end if; +end +$$ +call proc_top_b(1); +Starting ... +Starting ... +In prod_middle() +In prod_middle() +In proc_bottom() +In proc_bottom() +Doing something that works ... +Doing something that works ... +a b +1 1 +The end +The end +call proc_top_b(2); +Starting ... +Starting ... +In prod_middle() +In prod_middle() +In proc_bottom() +In proc_bottom() +Doing something that fail (simulate an error) ... +Doing something that fail (simulate an error) ... +Doing cleanup ! +Doing cleanup ! +ERROR 42S02: Unknown table 'no_such_table' +call proc_top_b(3); +Starting ... +Starting ... +In prod_middle() +In prod_middle() +In proc_bottom() +In proc_bottom() +Doing something that *SHOULD* works ... +Doing something that *SHOULD* works ... +a b +3 3 +The end +The end +call proc_top_b(1); +Starting ... +Starting ... +In prod_middle() +In prod_middle() +In proc_bottom() +In proc_bottom() +Doing something that works ... +Doing something that works ... +a b +1 1 +The end +The end +drop database demo; diff --git a/mysql-test/r/signal_demo3.result b/mysql-test/r/signal_demo3.result new file mode 100644 index 00000000000..fea41ec2ef9 --- /dev/null +++ b/mysql-test/r/signal_demo3.result @@ -0,0 +1,143 @@ +SET @start_global_value = @@global.max_error_count; +SELECT @start_global_value; +@start_global_value +64 +SET @start_session_value = @@session.max_error_count; +SELECT @start_session_value; +@start_session_value +64 +drop database if exists demo; +create database demo; +use demo; +create procedure proc_1() +begin +declare exit handler for sqlexception +resignal sqlstate '45000' set message_text='Oops in proc_1'; +call proc_2(); +end +$$ +create procedure proc_2() +begin +declare exit handler for sqlexception +resignal sqlstate '45000' set message_text='Oops in proc_2'; +call proc_3(); +end +$$ +create procedure proc_3() +begin +declare exit handler for sqlexception +resignal sqlstate '45000' set message_text='Oops in proc_3'; +call proc_4(); +end +$$ +create procedure proc_4() +begin +declare exit handler for sqlexception +resignal sqlstate '45000' set message_text='Oops in proc_4'; +call proc_5(); +end +$$ +create procedure proc_5() +begin +declare exit handler for sqlexception +resignal sqlstate '45000' set message_text='Oops in proc_5'; +call proc_6(); +end +$$ +create procedure proc_6() +begin +declare exit handler for sqlexception +resignal sqlstate '45000' set message_text='Oops in proc_6'; +call proc_7(); +end +$$ +create procedure proc_7() +begin +declare exit handler for sqlexception +resignal sqlstate '45000' set message_text='Oops in proc_7'; +call proc_8(); +end +$$ +create procedure proc_8() +begin +declare exit handler for sqlexception +resignal sqlstate '45000' set message_text='Oops in proc_8'; +call proc_9(); +end +$$ +create procedure proc_9() +begin +declare exit handler for sqlexception +resignal sqlstate '45000' set message_text='Oops in proc_9'; +## Do something that fails, to see how errors are reported +drop table oops_it_is_not_here; +end +$$ +call proc_1(); +ERROR 45000: Oops in proc_1 +show warnings; +Level Code Message +Error 1051 Unknown table 'oops_it_is_not_here' +Error 1642 Oops in proc_9 +Error 1642 Oops in proc_8 +Error 1642 Oops in proc_7 +Error 1642 Oops in proc_6 +Error 1642 Oops in proc_5 +Error 1642 Oops in proc_4 +Error 1642 Oops in proc_3 +Error 1642 Oops in proc_2 +Error 1642 Oops in proc_1 +SET @@session.max_error_count = 5; +SELECT @@session.max_error_count; +@@session.max_error_count +5 +call proc_1(); +ERROR 45000: Oops in proc_1 +show warnings; +Level Code Message +Error 1642 Oops in proc_5 +Error 1642 Oops in proc_4 +Error 1642 Oops in proc_3 +Error 1642 Oops in proc_2 +Error 1642 Oops in proc_1 +SET @@session.max_error_count = 7; +SELECT @@session.max_error_count; +@@session.max_error_count +7 +call proc_1(); +ERROR 45000: Oops in proc_1 +show warnings; +Level Code Message +Error 1642 Oops in proc_7 +Error 1642 Oops in proc_6 +Error 1642 Oops in proc_5 +Error 1642 Oops in proc_4 +Error 1642 Oops in proc_3 +Error 1642 Oops in proc_2 +Error 1642 Oops in proc_1 +SET @@session.max_error_count = 9; +SELECT @@session.max_error_count; +@@session.max_error_count +9 +call proc_1(); +ERROR 45000: Oops in proc_1 +show warnings; +Level Code Message +Error 1642 Oops in proc_9 +Error 1642 Oops in proc_8 +Error 1642 Oops in proc_7 +Error 1642 Oops in proc_6 +Error 1642 Oops in proc_5 +Error 1642 Oops in proc_4 +Error 1642 Oops in proc_3 +Error 1642 Oops in proc_2 +Error 1642 Oops in proc_1 +drop database demo; +SET @@global.max_error_count = @start_global_value; +SELECT @@global.max_error_count; +@@global.max_error_count +64 +SET @@session.max_error_count = @start_session_value; +SELECT @@session.max_error_count; +@@session.max_error_count +64 diff --git a/mysql-test/r/signal_sqlmode.result b/mysql-test/r/signal_sqlmode.result new file mode 100644 index 00000000000..8fed85eb4a9 --- /dev/null +++ b/mysql-test/r/signal_sqlmode.result @@ -0,0 +1,86 @@ +SET @save_sql_mode=@@sql_mode; +SET sql_mode=''; +drop procedure if exists p; +drop procedure if exists p2; +drop procedure if exists p3; +create procedure p() +begin +declare utf8_var VARCHAR(128) CHARACTER SET UTF8; +set utf8_var = concat(repeat('A', 128), 'X'); +select length(utf8_var), utf8_var; +end +$$ +create procedure p2() +begin +declare msg VARCHAR(129) CHARACTER SET UTF8; +set msg = concat(repeat('A', 128), 'X'); +select length(msg), msg; +signal sqlstate '55555' set message_text = msg; +end +$$ +create procedure p3() +begin +declare name VARCHAR(65) CHARACTER SET UTF8; +set name = concat(repeat('A', 64), 'X'); +select length(name), name; +signal sqlstate '55555' set +message_text = 'Message', +table_name = name; +end +$$ +call p; +length(utf8_var) utf8_var +128 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +Warnings: +Warning 1265 Data truncated for column 'utf8_var' at row 1 +call p2; +length(msg) msg +129 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX +ERROR 55555: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +call p3; +length(name) name +65 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX +ERROR 55555: Message +drop procedure p; +drop procedure p2; +drop procedure p3; +SET sql_mode='STRICT_ALL_TABLES'; +create procedure p() +begin +declare utf8_var VARCHAR(128) CHARACTER SET UTF8; +set utf8_var = concat(repeat('A', 128), 'X'); +select length(utf8_var), utf8_var; +end +$$ +create procedure p2() +begin +declare msg VARCHAR(129) CHARACTER SET UTF8; +set msg = concat(repeat('A', 128), 'X'); +select length(msg), msg; +signal sqlstate '55555' set message_text = msg; +end +$$ +create procedure p3() +begin +declare name VARCHAR(65) CHARACTER SET UTF8; +set name = concat(repeat('A', 64), 'X'); +select length(name), name; +signal sqlstate '55555' set +message_text = 'Message', +table_name = name; +end +$$ +call p; +ERROR 22001: Data too long for column 'utf8_var' at row 1 +call p2; +length(msg) msg +129 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX +ERROR HY000: Data too long for condition item 'MESSAGE_TEXT' +call p3; +length(name) name +65 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX +ERROR HY000: Data too long for condition item 'TABLE_NAME' +drop procedure p; +drop procedure p2; +drop procedure p3; +SET @@sql_mode=@save_sql_mode; diff --git a/mysql-test/r/sp-dynamic.result b/mysql-test/r/sp-dynamic.result index 34b76a9424f..cdfeb8ab020 100644 --- a/mysql-test/r/sp-dynamic.result +++ b/mysql-test/r/sp-dynamic.result @@ -97,8 +97,6 @@ end| call p1()| a 1 -Warnings: -Note 1051 Unknown table 't1' call p1()| a 1 @@ -371,9 +369,6 @@ call p1(@a)| create table t1 (a int) @rsql create table t2 (a int) -Warnings: -Note 1051 Unknown table 't1' -Note 1051 Unknown table 't2' select @a| @a 0 @@ -382,9 +377,6 @@ call p1(@a)| create table t1 (a int) @rsql create table t2 (a int) -Warnings: -Note 1051 Unknown table 't1' -Note 1051 Unknown table 't2' select @a| @a 0 diff --git a/mysql-test/r/sp-vars.result b/mysql-test/r/sp-vars.result index f5420a62f63..f532a5284a9 100644 --- a/mysql-test/r/sp-vars.result +++ b/mysql-test/r/sp-vars.result @@ -110,24 +110,6 @@ v7 v8 v9 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20 12.00 12.12 12.00 12.12 Warnings: -Warning 1264 Out of range value for column 'v1' at row 1 -Warning 1264 Out of range value for column 'v1u' at row 1 -Warning 1264 Out of range value for column 'v2' at row 1 -Warning 1264 Out of range value for column 'v2u' at row 1 -Warning 1264 Out of range value for column 'v3' at row 1 -Warning 1264 Out of range value for column 'v3u' at row 1 -Warning 1264 Out of range value for column 'v4' at row 1 -Warning 1264 Out of range value for column 'v4u' at row 1 -Warning 1264 Out of range value for column 'v5' at row 1 -Warning 1264 Out of range value for column 'v5u' at row 1 -Warning 1264 Out of range value for column 'v6' at row 1 -Warning 1264 Out of range value for column 'v6u' at row 1 -Warning 1366 Incorrect integer value: 'String 10 ' for column 'v10' at row 1 -Warning 1366 Incorrect integer value: 'String10' for column 'v11' at row 1 -Warning 1265 Data truncated for column 'v12' at row 1 -Warning 1265 Data truncated for column 'v13' at row 1 -Warning 1366 Incorrect integer value: 'Hello, world' for column 'v16' at row 1 -Note 1265 Data truncated for column 'v18' at row 1 Note 1265 Data truncated for column 'v20' at row 1 CALL sp_vars_check_assignment(); i1 i2 i3 i4 @@ -143,21 +125,6 @@ d1 d2 d3 d1 d2 d3 1234.00 1234.12 1234.12 Warnings: -Warning 1264 Out of range value for column 'i1' at row 1 -Warning 1264 Out of range value for column 'i2' at row 1 -Warning 1264 Out of range value for column 'i3' at row 1 -Warning 1264 Out of range value for column 'i4' at row 1 -Warning 1264 Out of range value for column 'i1' at row 1 -Warning 1264 Out of range value for column 'i2' at row 1 -Warning 1264 Out of range value for column 'i3' at row 1 -Warning 1264 Out of range value for column 'i4' at row 1 -Warning 1264 Out of range value for column 'u1' at row 1 -Warning 1264 Out of range value for column 'u2' at row 1 -Warning 1264 Out of range value for column 'u3' at row 1 -Warning 1264 Out of range value for column 'u4' at row 1 -Warning 1264 Out of range value for column 'u1' at row 1 -Warning 1264 Out of range value for column 'u2' at row 1 -Note 1265 Data truncated for column 'd3' at row 1 Note 1265 Data truncated for column 'd3' at row 1 SELECT sp_vars_check_ret1(); sp_vars_check_ret1() @@ -198,24 +165,6 @@ v7 v8 v9 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20 12.00 12.12 12.00 12.12 Warnings: -Warning 1264 Out of range value for column 'v1' at row 1 -Warning 1264 Out of range value for column 'v1u' at row 1 -Warning 1264 Out of range value for column 'v2' at row 1 -Warning 1264 Out of range value for column 'v2u' at row 1 -Warning 1264 Out of range value for column 'v3' at row 1 -Warning 1264 Out of range value for column 'v3u' at row 1 -Warning 1264 Out of range value for column 'v4' at row 1 -Warning 1264 Out of range value for column 'v4u' at row 1 -Warning 1264 Out of range value for column 'v5' at row 1 -Warning 1264 Out of range value for column 'v5u' at row 1 -Warning 1264 Out of range value for column 'v6' at row 1 -Warning 1264 Out of range value for column 'v6u' at row 1 -Warning 1366 Incorrect integer value: 'String 10 ' for column 'v10' at row 1 -Warning 1366 Incorrect integer value: 'String10' for column 'v11' at row 1 -Warning 1265 Data truncated for column 'v12' at row 1 -Warning 1265 Data truncated for column 'v13' at row 1 -Warning 1366 Incorrect integer value: 'Hello, world' for column 'v16' at row 1 -Note 1265 Data truncated for column 'v18' at row 1 Note 1265 Data truncated for column 'v20' at row 1 CALL sp_vars_check_assignment(); i1 i2 i3 i4 @@ -231,21 +180,6 @@ d1 d2 d3 d1 d2 d3 1234.00 1234.12 1234.12 Warnings: -Warning 1264 Out of range value for column 'i1' at row 1 -Warning 1264 Out of range value for column 'i2' at row 1 -Warning 1264 Out of range value for column 'i3' at row 1 -Warning 1264 Out of range value for column 'i4' at row 1 -Warning 1264 Out of range value for column 'i1' at row 1 -Warning 1264 Out of range value for column 'i2' at row 1 -Warning 1264 Out of range value for column 'i3' at row 1 -Warning 1264 Out of range value for column 'i4' at row 1 -Warning 1264 Out of range value for column 'u1' at row 1 -Warning 1264 Out of range value for column 'u2' at row 1 -Warning 1264 Out of range value for column 'u3' at row 1 -Warning 1264 Out of range value for column 'u4' at row 1 -Warning 1264 Out of range value for column 'u1' at row 1 -Warning 1264 Out of range value for column 'u2' at row 1 -Note 1265 Data truncated for column 'd3' at row 1 Note 1265 Data truncated for column 'd3' at row 1 SELECT sp_vars_check_ret1(); sp_vars_check_ret1() @@ -451,10 +385,6 @@ FF HEX(v10) FF Warnings: -Warning 1264 Out of range value for column 'v8' at row 1 -Warning 1264 Out of range value for column 'v9' at row 1 -Warning 1264 Out of range value for column 'v10' at row 1 -Warning 1264 Out of range value for column 'v1' at row 1 Warning 1264 Out of range value for column 'v5' at row 1 DROP PROCEDURE p1; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 3ad556b8c30..6f4755fcf37 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -526,8 +526,6 @@ end| delete from t1| create table t3 ( s char(16), d int)| call into_test4()| -Warnings: -Warning 1329 No data - zero rows fetched, selected, or processed select * from t3| s d into4 NULL @@ -1120,8 +1118,6 @@ end| select f9()| f9() 6 -Warnings: -Note 1051 Unknown table 't3' select f9() from t1 limit 1| f9() 6 @@ -1162,8 +1158,6 @@ drop temporary table t3| select f12_1()| f12_1() 3 -Warnings: -Note 1051 Unknown table 't3' select f12_1() from t1 limit 1| f12_1() 3 @@ -2069,12 +2063,7 @@ end if; insert into t4 values (2, rc, t3); end| call bug1863(10)| -Warnings: -Note 1051 Unknown table 'temp_t1' -Warning 1329 No data - zero rows fetched, selected, or processed call bug1863(10)| -Warnings: -Warning 1329 No data - zero rows fetched, selected, or processed select * from t4| f1 rc t3 2 0 NULL @@ -2339,11 +2328,7 @@ begin end| call bug4579_1()| call bug4579_1()| -Warnings: -Warning 1329 No data - zero rows fetched, selected, or processed call bug4579_1()| -Warnings: -Warning 1329 No data - zero rows fetched, selected, or processed drop procedure bug4579_1| drop procedure bug4579_2| drop table t3| @@ -3736,9 +3721,6 @@ Table Create Table tm1 CREATE TEMPORARY TABLE `tm1` ( `spv1` decimal(3,3) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -Warnings: -Warning 1264 Out of range value for column 'spv1' at row 1 -Warning 1366 Incorrect decimal value: 'test' for column 'spv1' at row 1 call bug12589_2()| Table Create Table tm1 CREATE TEMPORARY TABLE `tm1` ( @@ -6106,35 +6088,6 @@ bug5274_f2() x Warnings: Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 -Warning 1265 Data truncated for column 'bug5274_f1' at row 1 DROP FUNCTION bug5274_f1| DROP FUNCTION bug5274_f2| drop procedure if exists proc_21513| @@ -6229,20 +6182,17 @@ f1(2) 0 Warnings: Warning 1329 No data - zero rows fetched, selected, or processed -Warning 1329 No data - zero rows fetched, selected, or processed PREPARE s1 FROM 'SELECT f1(2)'; EXECUTE s1; f1(2) 0 Warnings: Warning 1329 No data - zero rows fetched, selected, or processed -Warning 1329 No data - zero rows fetched, selected, or processed EXECUTE s1; f1(2) 0 Warnings: Warning 1329 No data - zero rows fetched, selected, or processed -Warning 1329 No data - zero rows fetched, selected, or processed DROP PROCEDURE p1; DROP PROCEDURE p2; DROP FUNCTION f1; @@ -6254,6 +6204,7 @@ create procedure mysqltest_db1.sp_bug28551() begin end; call mysqltest_db1.sp_bug28551(); show warnings; Level Code Message +Note 1008 Can't drop database 'mysqltest_db1'; database doesn't exist drop database mysqltest_db1; drop database if exists mysqltest_db1; drop table if exists test.t1; diff --git a/mysql-test/r/sp_notembedded.result b/mysql-test/r/sp_notembedded.result index 831616f491b..228fe008447 100644 --- a/mysql-test/r/sp_notembedded.result +++ b/mysql-test/r/sp_notembedded.result @@ -21,9 +21,11 @@ end| call bug4902_2()| show warnings| Level Code Message +Note 1305 PROCEDURE bug4902_2 does not exist call bug4902_2()| show warnings| Level Code Message +Note 1305 PROCEDURE bug4902_2 does not exist drop procedure bug4902_2| drop table if exists t1| create table t1 ( diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index 241f4198bf7..a9e0d7f457d 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -315,8 +315,8 @@ MOD(col1,0) NULL NULL Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 INSERT INTO t1 (col1) VALUES(-129); ERROR 22003: Out of range value for column 'col1' at row 1 INSERT INTO t1 (col1) VALUES(128); @@ -343,7 +343,7 @@ SELECT MOD(col1,0) FROM t1 WHERE col1 > 0 LIMIT 1; MOD(col1,0) NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 UPDATE t1 SET col1 = col1 - 50 WHERE col1 < 0; ERROR 22003: Out of range value for column 'col1' at row 1 UPDATE t1 SET col2=col2 + 50 WHERE col2 > 0; @@ -353,16 +353,16 @@ ERROR 22012: Division by 0 set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO'; INSERT INTO t1 values (1/0,1/0); Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 set @@sql_mode='ansi,traditional'; SELECT MOD(col1,0) FROM t1 WHERE col1 > 0 LIMIT 2; MOD(col1,0) NULL NULL Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 INSERT INTO t1 (col1) VALUES (''); ERROR HY000: Incorrect integer value: '' for column 'col1' at row 1 INSERT INTO t1 (col1) VALUES ('a59b'); @@ -374,8 +374,8 @@ Warnings: Warning 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 values (1/0,1/0); Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 set @@sql_mode='ansi'; INSERT INTO t1 values (1/0,1/0); set @@sql_mode='ansi,traditional'; @@ -457,8 +457,8 @@ Warnings: Warning 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 values (1/0,1/0); Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 INSERT IGNORE INTO t1 VALUES(-32769,-1),(32768,65536); Warnings: Warning 1264 Out of range value for column 'col1' at row 1 @@ -541,8 +541,8 @@ Warnings: Warning 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 values (1/0,1/0); Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 INSERT IGNORE INTO t1 VALUES(-8388609,-1),(8388608,16777216); Warnings: Warning 1264 Out of range value for column 'col1' at row 1 @@ -625,8 +625,8 @@ Warnings: Warning 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 values (1/0,1/0); Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 INSERT IGNORE INTO t1 values (-2147483649, -1),(2147643648,4294967296); Warnings: Warning 1264 Out of range value for column 'col1' at row 1 @@ -707,8 +707,8 @@ Warnings: Warning 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 values (1/0,1/0); Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 INSERT IGNORE INTO t1 VALUES(-9223372036854775809,-1),(9223372036854775808,18446744073709551616); Warnings: Warning 1264 Out of range value for column 'col1' at row 1 @@ -794,7 +794,7 @@ Warnings: Note 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 values (1/0); Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 INSERT IGNORE INTO t1 VALUES(1000),(-1000); Warnings: Warning 1264 Out of range value for column 'col1' at row 1 @@ -861,7 +861,7 @@ Warnings: Warning 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 (col1) VALUES (1/0); Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 INSERT IGNORE INTO t1 VALUES (+3.4E+39,-3.4E+39); Warnings: Warning 1264 Out of range value for column 'col1' at row 1 @@ -910,7 +910,7 @@ Warnings: Warning 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 (col1) values (1/0); Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 INSERT IGNORE INTO t1 VALUES (+1.9E+309,-1.9E+309); ERROR 22007: Illegal double '1.9E+309' value found during parsing INSERT IGNORE INTO t1 VALUES ('+2.0E+309','-2.0E+309'); @@ -1080,13 +1080,13 @@ Warnings: Warning 1292 Truncated incorrect datetime value: '31.10.2004 15.30 abc' insert into t1 values(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i')); Warnings: -Error 1411 Incorrect datetime value: '32.10.2004 15.30' for function str_to_date +Warning 1411 Incorrect datetime value: '32.10.2004 15.30' for function str_to_date insert into t1 values(STR_TO_DATE('2004.12.12 22:22:33 AM','%Y.%m.%d %r')); Warnings: -Error 1411 Incorrect time value: '22:22:33 AM' for function str_to_date +Warning 1411 Incorrect time value: '22:22:33 AM' for function str_to_date insert into t1 values(STR_TO_DATE('2004.12.12 abc','%Y.%m.%d %T')); Warnings: -Error 1411 Incorrect time value: 'abc' for function str_to_date +Warning 1411 Incorrect time value: 'abc' for function str_to_date insert into t1 values(STR_TO_DATE('31.10.2004 15.30','%d.%m.%Y %H.%i')); insert into t1 values(STR_TO_DATE('2004.12.12 11:22:33 AM','%Y.%m.%d %r')); insert into t1 values(STR_TO_DATE('2004.12.12 10:22:59','%Y.%m.%d %T')); @@ -1104,9 +1104,9 @@ select count(*) from t1 where STR_TO_DATE('2004.12.12 10:22:61','%Y.%m.%d %T') I count(*) 7 Warnings: -Error 1411 Incorrect datetime value: '2004.12.12 10:22:61' for function str_to_date -Error 1411 Incorrect datetime value: '2004.12.12 10:22:61' for function str_to_date -Error 1411 Incorrect datetime value: '2004.12.12 10:22:61' for function str_to_date +Warning 1411 Incorrect datetime value: '2004.12.12 10:22:61' for function str_to_date +Warning 1411 Incorrect datetime value: '2004.12.12 10:22:61' for function str_to_date +Warning 1411 Incorrect datetime value: '2004.12.12 10:22:61' for function str_to_date drop table t1; create table t1 (col1 char(3), col2 integer); insert into t1 (col1) values (cast(1000 as char(3))); diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 4476735735c..000b08113c1 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1073,7 +1073,7 @@ NULL SET @x=2; UPDATE t1 SET i1 = @x; Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 SELECT @x; @x NULL @@ -1086,8 +1086,8 @@ NULL SET @x=4; UPDATE t1 SET i1 = @x; Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 SELECT @x; @x NULL @@ -1190,16 +1190,16 @@ create trigger t4_bu before update on t4 for each row set @t4_bu_called:=1| insert into t1 values(10, 10)| set @a:=1/0| Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 select 1/0 from t1| 1/0 NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 create trigger t1_bi before insert on t1 for each row set @a:=1/0| insert into t1 values(20, 20)| Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 drop trigger t1_bi| create trigger t1_bi before insert on t1 for each row begin @@ -1219,7 +1219,7 @@ end| set @check=0, @t4_bi_called=0, @t4_bu_called=0| insert into t1 values(30, 30)| Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 select @check, @t4_bi_called, @t4_bu_called| @check @t4_bi_called @t4_bu_called 2 1 1 diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index c3d1e400b23..1ad46821bb7 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -185,7 +185,7 @@ select 1e10/0e0; 1e10/0e0 NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 create table wl1612 (col1 int, col2 decimal(38,10), col3 numeric(38,10)); insert into wl1612 values(1,12345678901234567890.1234567890,12345678901234567890.1234567890); select * from wl1612; @@ -205,27 +205,27 @@ NULL NULL NULL Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 select col2/0 from wl1612; col2/0 NULL NULL NULL Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 select col3/0 from wl1612; col3/0 NULL NULL NULL Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 insert into wl1612 values(5,5000.0005,5000.0005); insert into wl1612 values(6,5000.0005,5000.0005); select sum(col2),sum(col3) from wl1612; @@ -788,12 +788,12 @@ select 1 / 1E-500; 1 / 1E-500 NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 select 1 / 0; 1 / 0 NULL Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 set sql_mode='ansi,traditional'; CREATE TABLE Sow6_2f (col1 NUMERIC(4,2)); INSERT INTO Sow6_2f VALUES (10.55); @@ -819,11 +819,11 @@ NULL NULL NULL Warnings: -Error 1365 Division by 0 -Error 1365 Division by 0 -Error 1365 Division by 0 -Error 1365 Division by 0 -Error 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 INSERT INTO Sow6_2f VALUES ('a59b'); ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1 drop table Sow6_2f; @@ -838,12 +838,12 @@ select 9999999999999999999999999999999999999999999999999999999999999999999999999 x 99999999999999999999999999999999999999999999999999999999999999999 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + 1 as x; x 100000000000000000000000000000000000000000000000000000000000000000 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' select 0.190287977636363637 + 0.040372670 * 0 - 0; 0.190287977636363637 + 0.040372670 * 0 - 0 0.190287977636363637 @@ -1380,15 +1380,15 @@ create table t1 (c1 decimal(64)); insert into t1 values( 89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000); Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1264 Out of range value for column 'c1' at row 1 insert into t1 values( 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999); Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1264 Out of range value for column 'c1' at row 1 insert into t1 values(1e100); Warnings: @@ -1432,7 +1432,7 @@ select cast(19999999999999999999 as unsigned); cast(19999999999999999999 as unsigned) 18446744073709551615 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' create table t1(a decimal(18)); insert into t1 values(123456789012345678); alter table t1 modify column a decimal(19); @@ -1444,12 +1444,12 @@ select cast(11.1234 as DECIMAL(3,2)); cast(11.1234 as DECIMAL(3,2)) 9.99 Warnings: -Error 1264 Out of range value for column 'cast(11.1234 as DECIMAL(3,2))' at row 1 +Warning 1264 Out of range value for column 'cast(11.1234 as DECIMAL(3,2))' at row 1 select * from (select cast(11.1234 as DECIMAL(3,2))) t; cast(11.1234 as DECIMAL(3,2)) 9.99 Warnings: -Error 1264 Out of range value for column 'cast(11.1234 as DECIMAL(3,2))' at row 1 +Warning 1264 Out of range value for column 'cast(11.1234 as DECIMAL(3,2))' at row 1 select cast(a as DECIMAL(3,2)) from (select 11.1233 as a UNION select 11.1234 @@ -1460,9 +1460,9 @@ cast(a as DECIMAL(3,2)) 9.99 9.99 Warnings: -Error 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 -Error 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 -Error 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 +Warning 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 +Warning 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 +Warning 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 select cast(a as DECIMAL(3,2)), count(*) from (select 11.1233 as a UNION select 11.1234 @@ -1471,10 +1471,10 @@ UNION select 12.1234 cast(a as DECIMAL(3,2)) count(*) 9.99 3 Warnings: -Error 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 -Error 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 -Error 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 -Error 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 +Warning 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 +Warning 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 +Warning 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 +Warning 1264 Out of range value for column 'cast(a as DECIMAL(3,2))' at row 1 create table t1 (s varchar(100)); insert into t1 values (0.00000000010000000000000000364321973154977415791655470655996396089904010295867919921875); drop table t1; @@ -1560,7 +1560,7 @@ select cast(143.481 as decimal(2,1)); cast(143.481 as decimal(2,1)) 9.9 Warnings: -Error 1264 Out of range value for column 'cast(143.481 as decimal(2,1))' at row 1 +Warning 1264 Out of range value for column 'cast(143.481 as decimal(2,1))' at row 1 select cast(-3.4 as decimal(2,1)); cast(-3.4 as decimal(2,1)) -3.4 @@ -1568,12 +1568,12 @@ select cast(99.6 as decimal(2,0)); cast(99.6 as decimal(2,0)) 99 Warnings: -Error 1264 Out of range value for column 'cast(99.6 as decimal(2,0))' at row 1 +Warning 1264 Out of range value for column 'cast(99.6 as decimal(2,0))' at row 1 select cast(-13.4 as decimal(2,1)); cast(-13.4 as decimal(2,1)) -9.9 Warnings: -Error 1264 Out of range value for column 'cast(-13.4 as decimal(2,1))' at row 1 +Warning 1264 Out of range value for column 'cast(-13.4 as decimal(2,1))' at row 1 select cast(98.6 as decimal(2,0)); cast(98.6 as decimal(2,0)) 99 @@ -1674,7 +1674,7 @@ CREATE TABLE t1 SELECT /* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001 AS c1; Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DESC t1; Field Type Null Key Default Extra c1 decimal(65,0) NO 0 @@ -1797,7 +1797,7 @@ CREATE TABLE t1 (a DECIMAL(30,30)); INSERT INTO t1 VALUES (0.1),(0.2),(0.3); CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1; Warnings: -Note 1265 Data truncated for column 'c1' at row 3 +Note 1265 Data truncated for column 'c1' at row 4 DESC t2; Field Type Null Key Default Extra c1 decimal(32,30) YES NULL diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index b5e374aaf8c..e23e8930ddb 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1111,8 +1111,8 @@ insert into v1 values(3); ERROR HY000: CHECK OPTION failed 'test.v1' insert ignore into v1 values (2),(3),(0); Warnings: -Error 1369 CHECK OPTION failed 'test.v1' -Error 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' select * from t1; a 1 @@ -1125,8 +1125,8 @@ create table t2 (a int); insert into t2 values (2),(3),(0); insert ignore into v1 SELECT a from t2; Warnings: -Error 1369 CHECK OPTION failed 'test.v1' -Error 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' select * from t1 order by a desc; a 1 @@ -1148,7 +1148,7 @@ a update v1 set a=a+1; update ignore v1,t2 set v1.a=v1.a+1 where v1.a=t2.a; Warnings: -Error 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' select * from t1; a 1 @@ -1182,7 +1182,7 @@ insert into v1 values (1) on duplicate key update a=2; ERROR HY000: CHECK OPTION failed 'test.v1' insert ignore into v1 values (1) on duplicate key update a=2; Warnings: -Error 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' select * from t1; a 1 @@ -1283,7 +1283,7 @@ insert ignore into v1 values (6); ERROR HY000: CHECK OPTION failed 'test.v1' insert ignore into v1 values (6),(3); Warnings: -Error 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' select * from t1; s1 3 @@ -1328,9 +1328,9 @@ delete from t1; load data infile '../../std_data/loaddata3.dat' ignore into table v1 fields terminated by '' enclosed by '' ignore 1 lines; Warnings: Warning 1366 Incorrect integer value: 'error ' for column 'a' at row 3 -Error 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' Warning 1366 Incorrect integer value: 'wrong end ' for column 'a' at row 4 -Error 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' select * from t1 order by a,b; a b 1 row 1 @@ -1354,7 +1354,7 @@ concat('|',a,'|') concat('|',b,'|') delete from t1; load data infile '../../std_data/loaddata2.dat' ignore into table v1 fields terminated by ',' enclosed by ''''; Warnings: -Error 1369 CHECK OPTION failed 'test.v1' +Warning 1369 CHECK OPTION failed 'test.v1' Warning 1261 Row 2 doesn't contain data for all columns select concat('|',a,'|'), concat('|',b,'|') from t1; concat('|',a,'|') concat('|',b,'|') diff --git a/mysql-test/suite/binlog/r/binlog_index.result b/mysql-test/suite/binlog/r/binlog_index.result index d49ceb00501..69d877c5adc 100644 --- a/mysql-test/suite/binlog/r/binlog_index.result +++ b/mysql-test/suite/binlog/r/binlog_index.result @@ -34,7 +34,7 @@ purge binary logs TO 'master-bin.000002'; ERROR HY000: Fatal error during log purge show warnings; Level Code Message -Error 1377 a problem with deleting master-bin.000001; consider examining correspondence of your binlog index file to the actual binlog files +Warning 1377 a problem with deleting master-bin.000001; consider examining correspondence of your binlog index file to the actual binlog files Error 1377 Fatal error during log purge reset master; End of tests diff --git a/mysql-test/suite/binlog/r/binlog_unsafe.result b/mysql-test/suite/binlog/r/binlog_unsafe.result index 4c2c32ad8f1..3047ff54cf0 100644 --- a/mysql-test/suite/binlog/r/binlog_unsafe.result +++ b/mysql-test/suite/binlog/r/binlog_unsafe.result @@ -43,12 +43,6 @@ END| CALL proc(); Warnings: Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. ---- Insert from stored function ---- CREATE FUNCTION func() RETURNS INT @@ -67,12 +61,6 @@ func() 0 Warnings: Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. ---- Insert from trigger ---- CREATE TRIGGER trig BEFORE INSERT ON trigger_table @@ -90,12 +78,6 @@ INSERT INTO trigger_table VALUES ('bye.'); Warnings: Note 1592 Statement may not be safe to log in statement format. Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. ---- Insert from prepared statement ---- PREPARE p1 FROM 'INSERT INTO t1 VALUES (@@global.sync_binlog)'; PREPARE p2 FROM 'INSERT INTO t1 VALUES (@@session.insert_id)'; @@ -155,12 +137,6 @@ func5() 0 Warnings: Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. ==== Variables that should *not* be unsafe ==== INSERT INTO t1 VALUES (@@session.pseudo_thread_id); INSERT INTO t1 VALUES (@@session.pseudo_thread_id); @@ -215,9 +191,6 @@ END| CALL p1(); Warnings: Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. -Note 1592 Statement may not be safe to log in statement format. DROP PROCEDURE p1; DROP TABLE t1; DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/innodb/r/innodb-zip.result b/mysql-test/suite/innodb/r/innodb-zip.result index b26c4112826..a59758c8673 100644 --- a/mysql-test/suite/innodb/r/innodb-zip.result +++ b/mysql-test/suite/innodb/r/innodb-zip.result @@ -198,13 +198,11 @@ create table t1 (id int primary key) engine = innodb key_block_size = 0; ERROR HY000: Can't create table 'test.t1' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 0. Valid values are [1, 2, 4, 8, 16] Error 1005 Can't create table 'test.t1' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 9; ERROR HY000: Can't create table 'test.t2' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] Error 1005 Can't create table 'test.t2' (errno: 1478) create table t3 (id int primary key) engine = innodb key_block_size = 1; create table t4 (id int primary key) engine = innodb key_block_size = 2; @@ -235,28 +233,24 @@ key_block_size = 8 row_format = redundant; ERROR HY000: Can't create table 'test.t2' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t2' (errno: 1478) create table t3 (id int primary key) engine = innodb key_block_size = 8 row_format = compact; ERROR HY000: Can't create table 'test.t3' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t3' (errno: 1478) create table t4 (id int primary key) engine = innodb key_block_size = 8 row_format = dynamic; ERROR HY000: Can't create table 'test.t4' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t4' (errno: 1478) create table t5 (id int primary key) engine = innodb key_block_size = 8 row_format = default; ERROR HY000: Can't create table 'test.t5' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t5' (errno: 1478) SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; @@ -268,24 +262,18 @@ key_block_size = 9 row_format = redundant; ERROR HY000: Can't create table 'test.t1' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t1' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 9 row_format = compact; ERROR HY000: Can't create table 'test.t2' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t2' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 9 row_format = dynamic; ERROR HY000: Can't create table 'test.t2' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t2' (errno: 1478) SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; @@ -295,43 +283,36 @@ create table t1 (id int primary key) engine = innodb key_block_size = 1; ERROR HY000: Can't create table 'test.t1' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t1' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 2; ERROR HY000: Can't create table 'test.t2' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t2' (errno: 1478) create table t3 (id int primary key) engine = innodb key_block_size = 4; ERROR HY000: Can't create table 'test.t3' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t3' (errno: 1478) create table t4 (id int primary key) engine = innodb key_block_size = 8; ERROR HY000: Can't create table 'test.t4' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t4' (errno: 1478) create table t5 (id int primary key) engine = innodb key_block_size = 16; ERROR HY000: Can't create table 'test.t5' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t5' (errno: 1478) create table t6 (id int primary key) engine = innodb row_format = compressed; ERROR HY000: Can't create table 'test.t6' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. Error 1005 Can't create table 'test.t6' (errno: 1478) create table t7 (id int primary key) engine = innodb row_format = dynamic; ERROR HY000: Can't create table 'test.t7' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. Error 1005 Can't create table 'test.t7' (errno: 1478) create table t8 (id int primary key) engine = innodb row_format = compact; create table t9 (id int primary key) engine = innodb row_format = redundant; @@ -347,43 +328,36 @@ create table t1 (id int primary key) engine = innodb key_block_size = 1; ERROR HY000: Can't create table 'test.t1' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t1' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 2; ERROR HY000: Can't create table 'test.t2' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t2' (errno: 1478) create table t3 (id int primary key) engine = innodb key_block_size = 4; ERROR HY000: Can't create table 'test.t3' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t3' (errno: 1478) create table t4 (id int primary key) engine = innodb key_block_size = 8; ERROR HY000: Can't create table 'test.t4' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t4' (errno: 1478) create table t5 (id int primary key) engine = innodb key_block_size = 16; ERROR HY000: Can't create table 'test.t5' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t5' (errno: 1478) create table t6 (id int primary key) engine = innodb row_format = compressed; ERROR HY000: Can't create table 'test.t6' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t6' (errno: 1478) create table t7 (id int primary key) engine = innodb row_format = dynamic; ERROR HY000: Can't create table 'test.t7' (errno: 1478) show errors; Level Code Message -Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t7' (errno: 1478) create table t8 (id int primary key) engine = innodb row_format = compact; create table t9 (id int primary key) engine = innodb row_format = redundant; diff --git a/mysql-test/suite/ndb/r/ndb_bitfield.result b/mysql-test/suite/ndb/r/ndb_bitfield.result index 59c4d420b22..826f3a98348 100644 --- a/mysql-test/suite/ndb/r/ndb_bitfield.result +++ b/mysql-test/suite/ndb/r/ndb_bitfield.result @@ -204,7 +204,7 @@ b int ERROR HY000: Can't create table 'test.t1' (errno: 906) show warnings; Level Code Message -Error 1296 Got error 906 'Unsupported attribute type in index' from NDB +Warning 1296 Got error 906 'Unsupported attribute type in index' from NDB Error 1005 Can't create table 'test.t1' (errno: 906) create table t1 ( pk1 int not null primary key, @@ -214,7 +214,7 @@ key(b) ERROR HY000: Can't create table 'test.t1' (errno: 906) show warnings; Level Code Message -Error 1296 Got error 906 'Unsupported attribute type in index' from NDB +Warning 1296 Got error 906 'Unsupported attribute type in index' from NDB Error 1005 Can't create table 'test.t1' (errno: 906) create table t1 ( pk1 int primary key, diff --git a/mysql-test/suite/ndb/r/ndb_dd_basic.result b/mysql-test/suite/ndb/r/ndb_dd_basic.result index 41e3d10fe5b..b956d3b0047 100644 --- a/mysql-test/suite/ndb/r/ndb_dd_basic.result +++ b/mysql-test/suite/ndb/r/ndb_dd_basic.result @@ -8,20 +8,20 @@ INITIAL_SIZE 16M UNDO_BUFFER_SIZE = 1M ENGINE=MYISAM; Warnings: -Error 1478 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' +Warning 1478 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' ALTER LOGFILE GROUP lg1 ADD UNDOFILE 'undofile02.dat' INITIAL_SIZE = 4M ENGINE=XYZ; Warnings: Warning 1286 Unknown table engine 'XYZ' -Error 1478 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' +Warning 1478 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' CREATE TABLESPACE ts1 ADD DATAFILE 'datafile.dat' USE LOGFILE GROUP lg1 INITIAL_SIZE 12M; Warnings: -Error 1478 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' +Warning 1478 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP' set storage_engine=ndb; CREATE LOGFILE GROUP lg1 ADD UNDOFILE 'undofile.dat' diff --git a/mysql-test/suite/ndb/r/ndb_dd_ddl.result b/mysql-test/suite/ndb/r/ndb_dd_ddl.result index d8d9e8631d5..2bf30f5c7fc 100644 --- a/mysql-test/suite/ndb/r/ndb_dd_ddl.result +++ b/mysql-test/suite/ndb/r/ndb_dd_ddl.result @@ -15,7 +15,7 @@ ENGINE NDB; ERROR HY000: Failed to create LOGFILE GROUP SHOW WARNINGS; Level Code Message -Error 1296 Got error 1514 'Currently there is a limit of one logfile group' from NDB +Warning 1296 Got error 1514 'Currently there is a limit of one logfile group' from NDB Error 1528 Failed to create LOGFILE GROUP CREATE LOGFILE GROUP lg1 ADD UNDOFILE 'undofile.dat' diff --git a/mysql-test/suite/ndb/r/ndb_gis.result b/mysql-test/suite/ndb/r/ndb_gis.result index 374d702c408..61d15b7cb98 100644 --- a/mysql-test/suite/ndb/r/ndb_gis.result +++ b/mysql-test/suite/ndb/r/ndb_gis.result @@ -463,7 +463,7 @@ drop table t1; End of 4.1 tests CREATE TABLE t1 (name VARCHAR(100), square GEOMETRY); Warnings: -Error 1478 Table storage engine 'ndbcluster' does not support the create option 'Binlog of table with BLOB attribute and no PK' +Warning 1478 Table storage engine 'ndbcluster' does not support the create option 'Binlog of table with BLOB attribute and no PK' INSERT INTO t1 VALUES("center", GeomFromText('POLYGON (( 0 0, 0 2, 2 2, 2 0, 0 0))')); INSERT INTO t1 VALUES("small", GeomFromText('POLYGON (( 0 0, 0 1, 1 1, 1 0, 0 0))')); INSERT INTO t1 VALUES("big", GeomFromText('POLYGON (( 0 0, 0 3, 3 3, 3 0, 0 0))')); @@ -1013,7 +1013,7 @@ drop table t1; End of 4.1 tests CREATE TABLE t1 (name VARCHAR(100), square GEOMETRY); Warnings: -Error 1478 Table storage engine 'ndbcluster' does not support the create option 'Binlog of table with BLOB attribute and no PK' +Warning 1478 Table storage engine 'ndbcluster' does not support the create option 'Binlog of table with BLOB attribute and no PK' INSERT INTO t1 VALUES("center", GeomFromText('POLYGON (( 0 0, 0 2, 2 2, 2 0, 0 0))')); INSERT INTO t1 VALUES("small", GeomFromText('POLYGON (( 0 0, 0 1, 1 1, 1 0, 0 0))')); INSERT INTO t1 VALUES("big", GeomFromText('POLYGON (( 0 0, 0 3, 3 3, 3 0, 0 0))')); diff --git a/mysql-test/suite/ndb/r/ndb_partition_error.result b/mysql-test/suite/ndb/r/ndb_partition_error.result index d86dc382185..df2db5c5f06 100644 --- a/mysql-test/suite/ndb/r/ndb_partition_error.result +++ b/mysql-test/suite/ndb/r/ndb_partition_error.result @@ -14,7 +14,7 @@ partition x3 values less than (20) nodegroup 14); ERROR HY000: Can't create table 'test.t1' (errno: 140) show warnings; Level Code Message -Error 1296 Got error 771 'Given NODEGROUP doesn't exist in this cluster' from NDB +Warning 1296 Got error 771 'Given NODEGROUP doesn't exist in this cluster' from NDB Error 1005 Can't create table 'test.t1' (errno: 140) CREATE TABLE t1 ( a int not null, diff --git a/mysql-test/suite/ndb/r/ndb_row_format.result b/mysql-test/suite/ndb/r/ndb_row_format.result index eea0692dd92..48a314c2fe9 100644 --- a/mysql-test/suite/ndb/r/ndb_row_format.result +++ b/mysql-test/suite/ndb/r/ndb_row_format.result @@ -8,7 +8,7 @@ ENGINE=NDB; ERROR HY000: Can't create table 'test.t1' (errno: 138) SHOW WARNINGS; Level Code Message -Error 1478 Table storage engine 'ndbcluster' does not support the create option 'Row format FIXED incompatible with variable sized attribute' +Warning 1478 Table storage engine 'ndbcluster' does not support the create option 'Row format FIXED incompatible with variable sized attribute' Error 1005 Can't create table 'test.t1' (errno: 138) CREATE TABLE t1 ( a INT KEY, diff --git a/mysql-test/suite/ndb/r/ndb_single_user.result b/mysql-test/suite/ndb/r/ndb_single_user.result index 8133e540d71..1d5f3041adb 100644 --- a/mysql-test/suite/ndb/r/ndb_single_user.result +++ b/mysql-test/suite/ndb/r/ndb_single_user.result @@ -9,7 +9,7 @@ ENGINE=NDB; ERROR HY000: Failed to create LOGFILE GROUP show warnings; Level Code Message -Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB +Warning 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB Error 1528 Failed to create LOGFILE GROUP create table t1 (a int key, b int unique, c int) engine ndb; CREATE LOGFILE GROUP lg1 @@ -25,14 +25,14 @@ ENGINE NDB; ERROR HY000: Failed to create TABLESPACE show warnings; Level Code Message -Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB +Warning 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB Error 1528 Failed to create TABLESPACE DROP LOGFILE GROUP lg1 ENGINE =NDB; ERROR HY000: Failed to drop LOGFILE GROUP show warnings; Level Code Message -Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB +Warning 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB Error 1529 Failed to drop LOGFILE GROUP CREATE TABLESPACE ts1 ADD DATAFILE 'datafile.dat' @@ -45,7 +45,7 @@ ENGINE NDB; ERROR HY000: Failed to alter: DROP DATAFILE show warnings; Level Code Message -Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB +Warning 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB Error 1533 Failed to alter: DROP DATAFILE ALTER TABLESPACE ts1 DROP DATAFILE 'datafile.dat' @@ -55,7 +55,7 @@ ENGINE NDB; ERROR HY000: Failed to drop TABLESPACE show warnings; Level Code Message -Error 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB +Warning 1296 Got error 299 'Operation not allowed or aborted due to single user mode' from NDB Error 1529 Failed to drop TABLESPACE DROP TABLESPACE ts1 ENGINE NDB; diff --git a/mysql-test/suite/rpl/r/rpl_EE_err.result b/mysql-test/suite/rpl/r/rpl_EE_err.result index 16fa931e303..8c1277445b2 100644 --- a/mysql-test/suite/rpl/r/rpl_EE_err.result +++ b/mysql-test/suite/rpl/r/rpl_EE_err.result @@ -8,4 +8,4 @@ create table t1 (a int) engine=myisam; flush tables; drop table if exists t1; Warnings: -Error 2 Can't find file: 't1' (errno: 2) +Warning 2 Can't find file: 't1' (errno: 2) diff --git a/mysql-test/suite/rpl/r/rpl_row_sp007_innodb.result b/mysql-test/suite/rpl/r/rpl_row_sp007_innodb.result index 9a2822835f8..5a6a9ace4c5 100644 --- a/mysql-test/suite/rpl/r/rpl_row_sp007_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_sp007_innodb.result @@ -22,8 +22,6 @@ END| < ---- Master selects-- > ------------------------- CALL test.p1(12); -Warnings: -Note 1051 Unknown table 't1' SELECT * FROM test.t1; num 12 diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index e92f3e96303..71d3d5a140b 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -694,3 +694,35 @@ SELECT 1 FROM t1 WHERE t1.a NOT IN DROP TABLE t1, t2; --echo End of 5.0 tests + +# +# Bug#36785: Wrong error message when group_concat() exceeds max length +# + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +CREATE TABLE t1 (a VARCHAR(6), b INT); +CREATE TABLE t2 (a VARCHAR(6), b INT); + +INSERT INTO t1 VALUES ('111111', 1); +INSERT INTO t1 VALUES ('222222', 2); +INSERT INTO t1 VALUES ('333333', 3); +INSERT INTO t1 VALUES ('444444', 4); +INSERT INTO t1 VALUES ('555555', 5); + +SET group_concat_max_len = 5; +SET @old_sql_mode = @@sql_mode, @@sql_mode = 'traditional'; + +SELECT GROUP_CONCAT(a), b FROM t1 GROUP BY b LIMIT 3; +--error ER_CUT_VALUE_GROUP_CONCAT +INSERT INTO t2 SELECT GROUP_CONCAT(a), b FROM t1 GROUP BY b; +UPDATE t1 SET a = '11111' WHERE b = 1; +UPDATE t1 SET a = '22222' WHERE b = 2; +--error ER_CUT_VALUE_GROUP_CONCAT +INSERT INTO t2 SELECT GROUP_CONCAT(a), b FROM t1 GROUP BY b; + +SET group_concat_max_len = DEFAULT; +SET @@sql_mode = @old_sql_mode; +DROP TABLE t1, t2; diff --git a/mysql-test/t/signal.test b/mysql-test/t/signal.test new file mode 100644 index 00000000000..bdb6625ba32 --- /dev/null +++ b/mysql-test/t/signal.test @@ -0,0 +1,2685 @@ +# Copyright (C) 2008 Sun Microsystems, Inc +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Tests for SIGNAL and RESIGNAL + +--echo # +--echo # PART 1: syntax +--echo # + +--echo # +--echo # Test every new reserved and non reserved keywords +--echo # + +--disable_warnings +drop table if exists signal_non_reserved; +--enable_warnings + +create table signal_non_reserved ( + class_origin int, + subclass_origin int, + constraint_catalog int, + constraint_schema int, + constraint_name int, + catalog_name int, + schema_name int, + table_name int, + column_name int, + cursor_name int, + message_text int, + sqlcode int +); + +drop table signal_non_reserved; + +--disable_warnings +drop table if exists diag_non_reserved; +--enable_warnings + +create table diag_non_reserved ( + diagnostics int, + current int, + stacked int, + exception int +); + +drop table diag_non_reserved; + +--disable_warnings +drop table if exists diag_cond_non_reserved; +--enable_warnings + +create table diag_cond_non_reserved ( + condition_identifier int, + condition_number int, + condition_name int, + connection_name int, + message_length int, + message_octet_length int, + parameter_mode int, + parameter_name int, + parameter_ordinal_position int, + returned_sqlstate int, + routine_catalog int, + routine_name int, + routine_schema int, + server_name int, + specific_name int, + trigger_catalog int, + trigger_name int, + trigger_schema int +); + +drop table diag_cond_non_reserved; + +--disable_warnings +drop table if exists diag_stmt_non_reserved; +--enable_warnings + +create table diag_stmt_non_reserved ( + number int, + more int, + command_function int, + command_function_code int, + dynamic_function int, + dynamic_function_code int, + row_count int, + transactions_committed int, + transactions_rolled_back int, + transaction_active int +); + +drop table diag_stmt_non_reserved; + +--disable_warnings +drop table if exists test_reserved; +--enable_warnings + +--error ER_PARSE_ERROR +create table test_reserved (signal int); + +--error ER_PARSE_ERROR +create table test_reserved (resignal int); + +--error ER_PARSE_ERROR +create table test_reserved (condition int); + +--echo # +--echo # Test the SIGNAL syntax +--echo # + +--disable_warnings +drop procedure if exists test_invalid; +drop procedure if exists test_signal_syntax; +drop function if exists test_signal_func; +--enable_warnings + +delimiter $$; + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL; +end $$ + +--error ER_SP_COND_MISMATCH +create procedure test_invalid() +begin + SIGNAL foo; +end $$ + +--error ER_SIGNAL_BAD_CONDITION_TYPE +create procedure test_invalid() +begin + DECLARE foo CONDITION FOR 1234; + SIGNAL foo; +end $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + SIGNAL SQLSTATE '23000'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + SIGNAL SQLSTATE VALUE '23000'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET CLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET SUBCLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET CONSTRAINT_CATALOG = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET CONSTRAINT_SCHEMA = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET CONSTRAINT_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET CATALOG_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET SCHEMA_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET TABLE_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET COLUMN_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET CURSOR_NAME = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MESSAGE_TEXT = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +--error ER_DUP_SIGNAL_SET +create procedure test_invalid() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET CLASS_ORIGIN = 'foo', CLASS_ORIGIN = 'bar'; +end $$ + +--error ER_DUP_SIGNAL_SET +create procedure test_invalid() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MESSAGE_TEXT = 'foo', MESSAGE_TEXT = 'bar'; +end $$ + +--error ER_DUP_SIGNAL_SET +create procedure test_invalid() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 'foo', MYSQL_ERRNO = 'bar'; +end $$ + +create procedure test_signal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET + CLASS_ORIGIN = 'foo', + SUBCLASS_ORIGIN = 'foo', + CONSTRAINT_CATALOG = 'foo', + CONSTRAINT_SCHEMA = 'foo', + CONSTRAINT_NAME = 'foo', + CATALOG_NAME = 'foo', + SCHEMA_NAME = 'foo', + TABLE_NAME = 'foo', + COLUMN_NAME = 'foo', + CURSOR_NAME = 'foo', + MESSAGE_TEXT = 'foo', + MYSQL_ERRNO = 'foo'; +end $$ +drop procedure test_signal_syntax $$ + +--error ER_SP_BAD_SQLSTATE +SIGNAL SQLSTATE '00000' $$ + +--error ER_SP_BAD_SQLSTATE +SIGNAL SQLSTATE '00001' $$ + +--error ER_SP_BAD_SQLSTATE +create procedure test_invalid() +begin + SIGNAL SQLSTATE '00000'; +end $$ + +--error ER_SP_BAD_SQLSTATE +create procedure test_invalid() +begin + SIGNAL SQLSTATE '00001'; +end $$ + +--echo # +--echo # Test conditions information that SIGNAL can not set +--echo # + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET bla_bla = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET CONDITION_IDENTIFIER = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET CONDITION_NUMBER = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET CONNECTION_NAME = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET MESSAGE_LENGTH = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET MESSAGE_OCTET_LENGTH = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET PARAMETER_MODE = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET PARAMETER_NAME = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET PARAMETER_ORDINAL_POSITION = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET RETURNED_SQLSTATE = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET ROUTINE_CATALOG = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET ROUTINE_NAME = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET ROUTINE_SCHEMA = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET SERVER_NAME = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET SPECIFIC_NAME = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET TRIGGER_CATALOG = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET TRIGGER_NAME = 'foo'; +end $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + SIGNAL SQLSTATE '12345' SET TRIGGER_SCHEMA = 'foo'; +end $$ + +delimiter ;$$ + +--echo # +--echo # Test the RESIGNAL syntax +--echo # + +--disable_warnings +drop procedure if exists test_invalid; +drop procedure if exists test_resignal_syntax; +--enable_warnings + +delimiter $$; + +--error ER_SP_COND_MISMATCH +create procedure test_invalid() +begin + RESIGNAL foo; +end $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL; +end $$ +drop procedure test_resignal_syntax $$ + +--error ER_SIGNAL_BAD_CONDITION_TYPE +create procedure test_invalid() +begin + DECLARE foo CONDITION FOR 1234; + RESIGNAL foo; +end $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SQLSTATE '23000'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SQLSTATE VALUE '23000'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET CLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET CLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET SUBCLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET SUBCLASS_ORIGIN = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET CONSTRAINT_CATALOG = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET CONSTRAINT_CATALOG = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET CONSTRAINT_SCHEMA = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET CONSTRAINT_SCHEMA = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET CONSTRAINT_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET CONSTRAINT_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET CATALOG_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET CATALOG_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET SCHEMA_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET SCHEMA_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET TABLE_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET TABLE_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET COLUMN_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET COLUMN_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET CURSOR_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET CURSOR_NAME = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET MESSAGE_TEXT = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET MESSAGE_TEXT = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + RESIGNAL SET MYSQL_ERRNO = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET MYSQL_ERRNO = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +--error ER_DUP_SIGNAL_SET +create procedure test_invalid() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET CLASS_ORIGIN = 'foo', CLASS_ORIGIN = 'bar'; +end $$ + +--error ER_DUP_SIGNAL_SET +create procedure test_invalid() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET MESSAGE_TEXT = 'foo', MESSAGE_TEXT = 'bar'; +end $$ + +--error ER_DUP_SIGNAL_SET +create procedure test_invalid() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET MYSQL_ERRNO = 'foo', MYSQL_ERRNO = 'bar'; +end $$ + +create procedure test_resignal_syntax() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + RESIGNAL foo SET + CLASS_ORIGIN = 'foo', + SUBCLASS_ORIGIN = 'foo', + CONSTRAINT_CATALOG = 'foo', + CONSTRAINT_SCHEMA = 'foo', + CONSTRAINT_NAME = 'foo', + CATALOG_NAME = 'foo', + SCHEMA_NAME = 'foo', + TABLE_NAME = 'foo', + COLUMN_NAME = 'foo', + CURSOR_NAME = 'foo', + MESSAGE_TEXT = 'foo'; +end $$ +drop procedure test_resignal_syntax $$ + +--error ER_SP_BAD_SQLSTATE +create procedure test_invalid() +begin + RESIGNAL SQLSTATE '00000'; +end $$ + +--error ER_SP_BAD_SQLSTATE +create procedure test_invalid() +begin + RESIGNAL SQLSTATE '00001'; +end $$ + +delimiter ;$$ + +--echo # +--echo # PART 2: non preparable statements +--echo # + +--error ER_UNSUPPORTED_PS +prepare stmt from 'SIGNAL SQLSTATE \'23000\''; + +--error ER_UNSUPPORTED_PS +prepare stmt from 'RESIGNAL SQLSTATE \'23000\''; + +--echo # +--echo # PART 3: runtime execution +--echo # + +--disable_warnings +drop procedure if exists test_signal; +drop procedure if exists test_resignal; +drop table if exists t_warn; +drop table if exists t_cursor; +--enable_warnings + +# Helper tables +create table t_warn(a integer(2)); +create table t_cursor(a integer); + +--echo # +--echo # SIGNAL can also appear in a query +--echo # + +--error ER_SP_COND_MISMATCH +SIGNAL foo; + +SIGNAL SQLSTATE '01000'; + +--error ER_SIGNAL_NOT_FOUND +SIGNAL SQLSTATE '02000'; + +--error ER_SIGNAL_EXCEPTION +SIGNAL SQLSTATE '23000'; + +--error ER_SIGNAL_EXCEPTION +SIGNAL SQLSTATE VALUE '23000'; + +--error ER_WRONG_VALUE_FOR_VAR +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 65536; + +--error ER_WRONG_VALUE_FOR_VAR +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 99999; + +--error ER_WRONG_VALUE_FOR_VAR +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 4294967295; + +--error ER_WRONG_VALUE_FOR_VAR +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 0; + +--error ER_PARSE_ERROR +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = -1; + +--error 65535 +SIGNAL SQLSTATE 'HY000' SET MYSQL_ERRNO = 65535; + +--echo # +--echo # RESIGNAL can also appear in a query +--echo # + +--error ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER +RESIGNAL; + +--error ER_SP_COND_MISMATCH +RESIGNAL foo; + +--error ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER +RESIGNAL SQLSTATE '12345'; + +--error ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER +RESIGNAL SQLSTATE VALUE '12345'; + +--echo # +--echo # Different kind of SIGNAL conditions +--echo # + +delimiter $$; + +create procedure test_signal() +begin + # max range + DECLARE foo CONDITION FOR SQLSTATE 'AABBB'; + SIGNAL foo SET MYSQL_ERRNO = 65535; +end $$ + +--error 65535 +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # max range + DECLARE foo CONDITION FOR SQLSTATE 'AABBB'; + SIGNAL foo SET MYSQL_ERRNO = 65536; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Error + DECLARE foo CONDITION FOR SQLSTATE '99999'; + SIGNAL foo SET MYSQL_ERRNO = 9999; +end $$ + +--error 9999 +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # warning + DECLARE too_few_records CONDITION FOR SQLSTATE '01000'; + SIGNAL too_few_records SET MYSQL_ERRNO = 1261; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Not found + DECLARE sp_fetch_no_data CONDITION FOR SQLSTATE '02000'; + SIGNAL sp_fetch_no_data SET MYSQL_ERRNO = 1329; +end $$ + +--error ER_SP_FETCH_NO_DATA +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Error + DECLARE sp_cursor_already_open CONDITION FOR SQLSTATE '24000'; + SIGNAL sp_cursor_already_open SET MYSQL_ERRNO = 1325; +end $$ + +--error ER_SP_CURSOR_ALREADY_OPEN +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Severe error + DECLARE lock_deadlock CONDITION FOR SQLSTATE '40001'; + SIGNAL lock_deadlock SET MYSQL_ERRNO = 1213; +end $$ + +--error ER_LOCK_DEADLOCK +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Unknown -> error + DECLARE foo CONDITION FOR SQLSTATE "99999"; + SIGNAL foo; +end $$ + +--error ER_SIGNAL_EXCEPTION +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # warning, no subclass + DECLARE warn CONDITION FOR SQLSTATE "01000"; + SIGNAL warn; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # warning, with subclass + DECLARE warn CONDITION FOR SQLSTATE "01123"; + SIGNAL warn; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Not found, no subclass + DECLARE not_found CONDITION FOR SQLSTATE "02000"; + SIGNAL not_found; +end $$ + +--error ER_SIGNAL_NOT_FOUND +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Not found, with subclass + DECLARE not_found CONDITION FOR SQLSTATE "02XXX"; + SIGNAL not_found; +end $$ + +--error ER_SIGNAL_NOT_FOUND +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Error, no subclass + DECLARE error CONDITION FOR SQLSTATE "12000"; + SIGNAL error; +end $$ + +--error ER_SIGNAL_EXCEPTION +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Error, with subclass + DECLARE error CONDITION FOR SQLSTATE "12ABC"; + SIGNAL error; +end $$ + +--error ER_SIGNAL_EXCEPTION +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Severe error, no subclass + DECLARE error CONDITION FOR SQLSTATE "40000"; + SIGNAL error; +end $$ + +--error ER_SIGNAL_EXCEPTION +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + # Severe error, with subclass + DECLARE error CONDITION FOR SQLSTATE "40001"; + SIGNAL error; +end $$ + +--error ER_SIGNAL_EXCEPTION +call test_signal() $$ +drop procedure test_signal $$ + +--echo # +--echo # Test the scope of condition +--echo # + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '99999'; + begin + DECLARE foo CONDITION FOR 8888; + end; + SIGNAL foo SET MYSQL_ERRNO=9999; /* outer */ +end $$ + +--error 9999 +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR 9999; + begin + DECLARE foo CONDITION FOR SQLSTATE '88888'; + SIGNAL foo SET MYSQL_ERRNO=8888; /* inner */ + end; +end $$ + +--error 8888 +call test_signal() $$ +drop procedure test_signal $$ + +--echo # +--echo # Test SET MYSQL_ERRNO +--echo # + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '99999'; + SIGNAL foo SET MYSQL_ERRNO = 1111; +end $$ + +--error 1111 +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01000"; + SIGNAL warn SET MYSQL_ERRNO = 1111; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02000"; + SIGNAL not_found SET MYSQL_ERRNO = 1111; +end $$ + +--error 1111 +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE "55000"; + SIGNAL error SET MYSQL_ERRNO = 1111; +end $$ + +--error 1111 +call test_signal() $$ +drop procedure test_signal $$ + +--echo # +--echo # Test SET MESSAGE_TEXT +--echo # + +--error ER_SIGNAL_EXCEPTION +SIGNAL SQLSTATE '77777' SET MESSAGE_TEXT='' $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '77777'; + SIGNAL foo SET + MESSAGE_TEXT = "", + MYSQL_ERRNO=5678; +end $$ + +--error 5678 +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '99999'; + SIGNAL foo SET + MESSAGE_TEXT = "Something bad happened", + MYSQL_ERRNO=9999; +end $$ + +--error 9999 +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01000"; + SIGNAL warn SET MESSAGE_TEXT = "Something bad happened"; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02000"; + SIGNAL not_found SET MESSAGE_TEXT = "Something bad happened"; +end $$ + +--error ER_SIGNAL_NOT_FOUND +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE "55000"; + SIGNAL error SET MESSAGE_TEXT = "Something bad happened"; +end $$ + +--error ER_SIGNAL_EXCEPTION +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE something CONDITION FOR SQLSTATE "01000"; + SIGNAL something SET MESSAGE_TEXT = _utf8 "This is a UTF8 text"; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE something CONDITION FOR SQLSTATE "01000"; + SIGNAL something SET MESSAGE_TEXT = ""; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01111"; + SIGNAL warn SET MESSAGE_TEXT = "á a"; +end $$ + +call test_signal() $$ +show warnings $$ +drop procedure test_signal $$ + +--echo # +--echo # Test SET complex expressions +--echo # + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + MYSQL_ERRNO = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + CLASS_ORIGIN = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + SUBCLASS_ORIGIN = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + CONSTRAINT_CATALOG = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + CONSTRAINT_SCHEMA = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + CONSTRAINT_NAME = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + CATALOG_NAME = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + SCHEMA_NAME = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + TABLE_NAME = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + COLUMN_NAME = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + CURSOR_NAME = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE '99999'; + SIGNAL error SET + MESSAGE_TEXT = NULL; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE something CONDITION FOR SQLSTATE '99999'; + DECLARE message_text VARCHAR(64) DEFAULT "Local string variable"; + DECLARE sqlcode INTEGER DEFAULT 1234; + + SIGNAL something SET + MESSAGE_TEXT = message_text, + MYSQL_ERRNO = sqlcode; +end $$ + +--error 1234 +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal(message_text VARCHAR(64), sqlcode INTEGER) +begin + DECLARE something CONDITION FOR SQLSTATE "12345"; + + SIGNAL something SET + MESSAGE_TEXT = message_text, + MYSQL_ERRNO = sqlcode; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal("Parameter string", NULL) $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal(NULL, 1234) $$ + +--error 5678 +call test_signal("Parameter string", 5678) $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE something CONDITION FOR SQLSTATE "AABBB"; + + SIGNAL something SET + MESSAGE_TEXT = @message_text, + MYSQL_ERRNO = @sqlcode; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ + +set @sqlcode= 12 $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ + +set @message_text= "User variable" $$ + +--error 12 +call test_signal() $$ +drop procedure test_signal $$ + +--error ER_PARSE_ERROR +create procedure test_invalid() +begin + DECLARE something CONDITION FOR SQLSTATE "AABBB"; + + SIGNAL something SET + MESSAGE_TEXT = @message_text := 'illegal', + MYSQL_ERRNO = @sqlcode := 1234; +end $$ + +create procedure test_signal() +begin + DECLARE aaa VARCHAR(64); + DECLARE bbb VARCHAR(64); + DECLARE ccc VARCHAR(64); + DECLARE ddd VARCHAR(64); + DECLARE eee VARCHAR(64); + DECLARE fff VARCHAR(64); + DECLARE ggg VARCHAR(64); + DECLARE hhh VARCHAR(64); + DECLARE iii VARCHAR(64); + DECLARE jjj VARCHAR(64); + DECLARE kkk VARCHAR(64); + + DECLARE warn CONDITION FOR SQLSTATE "01234"; + + set aaa= repeat("A", 64); + set bbb= repeat("B", 64); + set ccc= repeat("C", 64); + set ddd= repeat("D", 64); + set eee= repeat("E", 64); + set fff= repeat("F", 64); + set ggg= repeat("G", 64); + set hhh= repeat("H", 64); + set iii= repeat("I", 64); + set jjj= repeat("J", 64); + set kkk= repeat("K", 64); + + SIGNAL warn SET + CLASS_ORIGIN = aaa, + SUBCLASS_ORIGIN = bbb, + CONSTRAINT_CATALOG = ccc, + CONSTRAINT_SCHEMA = ddd, + CONSTRAINT_NAME = eee, + CATALOG_NAME = fff, + SCHEMA_NAME = ggg, + TABLE_NAME = hhh, + COLUMN_NAME = iii, + CURSOR_NAME = jjj, + MESSAGE_TEXT = kkk, + MYSQL_ERRNO = 65535; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01234"; + + SIGNAL warn SET + MYSQL_ERRNO = 999999999999999999999999999999999999999999999999999; +end $$ + +--error ER_WRONG_VALUE_FOR_VAR +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE aaax VARCHAR(65); + DECLARE bbbx VARCHAR(65); + DECLARE cccx VARCHAR(65); + DECLARE dddx VARCHAR(65); + DECLARE eeex VARCHAR(65); + DECLARE fffx VARCHAR(65); + DECLARE gggx VARCHAR(65); + DECLARE hhhx VARCHAR(65); + DECLARE iiix VARCHAR(65); + DECLARE jjjx VARCHAR(65); + DECLARE kkkx VARCHAR(65); + DECLARE lllx VARCHAR(129); + + DECLARE warn CONDITION FOR SQLSTATE "01234"; + + set aaax= concat(repeat("A", 64), "X"); + set bbbx= concat(repeat("B", 64), "X"); + set cccx= concat(repeat("C", 64), "X"); + set dddx= concat(repeat("D", 64), "X"); + set eeex= concat(repeat("E", 64), "X"); + set fffx= concat(repeat("F", 64), "X"); + set gggx= concat(repeat("G", 64), "X"); + set hhhx= concat(repeat("H", 64), "X"); + set iiix= concat(repeat("I", 64), "X"); + set jjjx= concat(repeat("J", 64), "X"); + set kkkx= concat(repeat("K", 64), "X"); + set lllx= concat(repeat("1", 100), + repeat("2", 20), + repeat("8", 8), + "X"); + + SIGNAL warn SET + CLASS_ORIGIN = aaax, + SUBCLASS_ORIGIN = bbbx, + CONSTRAINT_CATALOG = cccx, + CONSTRAINT_SCHEMA = dddx, + CONSTRAINT_NAME = eeex, + CATALOG_NAME = fffx, + SCHEMA_NAME = gggx, + TABLE_NAME = hhhx, + COLUMN_NAME = iiix, + CURSOR_NAME = jjjx, + MESSAGE_TEXT = lllx, + MYSQL_ERRNO = 10000; +end $$ + +#NOTE: the warning text for ER_TRUNCATED_WRONG_VALUE contains +# value: '%-.128s', so the warning printed truncates the value too, +# which affects MESSAGE_TEXT (the X is missing) + +call test_signal() $$ +drop procedure test_signal $$ + +# Test that HANDLER can catch conditions raised by SIGNAL + +create procedure test_signal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01234"; + DECLARE CONTINUE HANDLER for SQLSTATE "01234" + begin + select "Caught by SQLSTATE"; + end; + + SIGNAL warn SET + MESSAGE_TEXT = "Raising a warning", + MYSQL_ERRNO = 1012; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01234"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "Caught by number"; + end; + + SIGNAL warn SET + MESSAGE_TEXT = "Raising a warning", + MYSQL_ERRNO = 1012; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01234"; + DECLARE CONTINUE HANDLER for SQLWARNING + begin + select "Caught by SQLWARNING"; + end; + + SIGNAL warn SET + MESSAGE_TEXT = "Raising a warning", + MYSQL_ERRNO = 1012; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; + DECLARE CONTINUE HANDLER for SQLSTATE "02ABC" + begin + select "Caught by SQLSTATE"; + end; + + SIGNAL not_found SET + MESSAGE_TEXT = "Raising a not found", + MYSQL_ERRNO = 1012; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "Caught by number"; + end; + + SIGNAL not_found SET + MESSAGE_TEXT = "Raising a not found", + MYSQL_ERRNO = 1012; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; + DECLARE CONTINUE HANDLER for NOT FOUND + begin + select "Caught by NOT FOUND"; + end; + + SIGNAL not_found SET + MESSAGE_TEXT = "Raising a not found", + MYSQL_ERRNO = 1012; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE "55555"; + DECLARE CONTINUE HANDLER for SQLSTATE "55555" + begin + select "Caught by SQLSTATE"; + end; + + SIGNAL error SET + MESSAGE_TEXT = "Raising an error", + MYSQL_ERRNO = 1012; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE "55555"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "Caught by number"; + end; + + SIGNAL error SET + MESSAGE_TEXT = "Raising an error", + MYSQL_ERRNO = 1012; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE error CONDITION FOR SQLSTATE "55555"; + DECLARE CONTINUE HANDLER for SQLEXCEPTION + begin + select "Caught by SQLEXCEPTION"; + end; + + SIGNAL error SET + MESSAGE_TEXT = "Raising an error", + MYSQL_ERRNO = 1012; +end $$ + +call test_signal() $$ +drop procedure test_signal $$ + +--echo # +--echo # Test where SIGNAL can be used +--echo # + +create function test_signal_func() returns integer +begin + DECLARE warn CONDITION FOR SQLSTATE "01XXX"; + + SIGNAL warn SET + MESSAGE_TEXT = "This function SIGNAL a warning", + MYSQL_ERRNO = 1012; + + return 5; +end $$ + +select test_signal_func() $$ +drop function test_signal_func $$ + +create function test_signal_func() returns integer +begin + DECLARE not_found CONDITION FOR SQLSTATE "02XXX"; + + SIGNAL not_found SET + MESSAGE_TEXT = "This function SIGNAL not found", + MYSQL_ERRNO = 1012; + + return 5; +end $$ + +--error 1012 +select test_signal_func() $$ +drop function test_signal_func $$ + +create function test_signal_func() returns integer +begin + DECLARE error CONDITION FOR SQLSTATE "50000"; + + SIGNAL error SET + MESSAGE_TEXT = "This function SIGNAL an error", + MYSQL_ERRNO = 1012; + + return 5; +end $$ + +--error 1012 +select test_signal_func() $$ +drop function test_signal_func $$ + +--disable_warnings +drop table if exists t1 $$ +--enable_warnings + +create table t1 (a integer) $$ + +create trigger t1_ai after insert on t1 for each row +begin + DECLARE msg VARCHAR(128); + DECLARE warn CONDITION FOR SQLSTATE "01XXX"; + + set msg= concat("This trigger SIGNAL a warning, a=", NEW.a); + SIGNAL warn SET + MESSAGE_TEXT = msg, + MYSQL_ERRNO = 1012; +end $$ + +insert into t1 values (1), (2) $$ + +drop trigger t1_ai $$ + +create trigger t1_ai after insert on t1 for each row +begin + DECLARE msg VARCHAR(128); + DECLARE not_found CONDITION FOR SQLSTATE "02XXX"; + + set msg= concat("This trigger SIGNAL a not found, a=", NEW.a); + SIGNAL not_found SET + MESSAGE_TEXT = msg, + MYSQL_ERRNO = 1012; +end $$ + +--error 1012 +insert into t1 values (3), (4) $$ + +drop trigger t1_ai $$ + +create trigger t1_ai after insert on t1 for each row +begin + DECLARE msg VARCHAR(128); + DECLARE error CONDITION FOR SQLSTATE "03XXX"; + + set msg= concat("This trigger SIGNAL an error, a=", NEW.a); + SIGNAL error SET + MESSAGE_TEXT = msg, + MYSQL_ERRNO = 1012; +end $$ + +--error 1012 +insert into t1 values (5), (6) $$ + +drop table t1 $$ + +create table t1 (errno integer, msg varchar(128)) $$ + +create trigger t1_ai after insert on t1 for each row +begin + DECLARE warn CONDITION FOR SQLSTATE "01XXX"; + + SIGNAL warn SET + MESSAGE_TEXT = NEW.msg, + MYSQL_ERRNO = NEW.errno; +end $$ + +insert into t1 set errno=1012, msg='Warning message 1 in trigger' $$ +insert into t1 set errno=1013, msg='Warning message 2 in trigger' $$ + +drop table t1 $$ + +--disable_warnings +drop table if exists t1 $$ +drop procedure if exists p1 $$ +drop function if exists f1 $$ +--enable_warnings + +create table t1 (s1 int) $$ +insert into t1 values (1) $$ + +create procedure p1() +begin + declare a int; + declare c cursor for select f1() from t1; + declare continue handler for sqlstate '03000' + select "caught 03000"; + declare continue handler for 1326 + select "caught cursor is not open"; + + select "Before open"; + open c; + select "Before fetch"; + fetch c into a; + select "Before close"; + close c; +end $$ + +create function f1() returns int +begin + signal sqlstate '03000'; + return 5; +end $$ + +## FIXME : MEMORY plugin warning, valgrind leak, bug#36518 +## call p1() $$ + +drop table t1 $$ +drop procedure p1 $$ +drop function f1 $$ + +--echo # +--echo # Test the RESIGNAL runtime +--echo # + +# 6 tests: +# {Signaled warning, Signaled Not Found, Signaled Error, +# warning, not found, error} --> RESIGNAL + +create procedure test_resignal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01234"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL; + select "after RESIGNAL"; + end; + + SIGNAL warn SET + MESSAGE_TEXT = "Raising a warning", + MYSQL_ERRNO = 1012; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02222"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL; + select "after RESIGNAL"; + end; + + SIGNAL not_found SET + MESSAGE_TEXT = "Raising a not found", + MYSQL_ERRNO = 1012; +end $$ + +--error 1012 +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE error CONDITION FOR SQLSTATE "55555"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL; + select "after RESIGNAL"; + end; + + SIGNAL error SET + MESSAGE_TEXT = "Raising an error", + MYSQL_ERRNO = 1012; +end $$ + +--error 1012 +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlwarning + begin + select "before RESIGNAL"; + RESIGNAL; + select "after RESIGNAL"; + end; + + insert into t_warn set a= 9999999999999999; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE x integer; + DECLARE c cursor for select * from t_cursor; + DECLARE CONTINUE HANDLER for not found + begin + select "before RESIGNAL"; + RESIGNAL; + select "after RESIGNAL"; + end; + + open c; + fetch c into x; + close c; +end $$ + +--error ER_SP_FETCH_NO_DATA +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlexception + begin + select "before RESIGNAL"; + RESIGNAL; + select "after RESIGNAL"; + end; + + drop table no_such_table; +end $$ + +--error ER_BAD_TABLE_ERROR +call test_resignal() $$ +drop procedure test_resignal $$ + +# 6 tests: +# {Signaled warning, Signaled Not Found, Signaled Error, +# warning, not found, error} --> RESIGNAL SET ... + +create procedure test_resignal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01234"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SET + MESSAGE_TEXT = "RESIGNAL of a warning", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL warn SET + MESSAGE_TEXT = "Raising a warning", + MYSQL_ERRNO = 1012; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02111"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SET + MESSAGE_TEXT = "RESIGNAL of a not found", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL not_found SET + MESSAGE_TEXT = "Raising a not found", + MYSQL_ERRNO = 1012; +end $$ + +--error 5555 +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE error CONDITION FOR SQLSTATE "33333"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SET + MESSAGE_TEXT = "RESIGNAL of an error", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL error SET + MESSAGE_TEXT = "Raising an error", + MYSQL_ERRNO = 1012; +end $$ + +--error 5555 +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlwarning + begin + select "before RESIGNAL"; + RESIGNAL SET + MESSAGE_TEXT = "RESIGNAL of a warning", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + insert into t_warn set a= 9999999999999999; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE x integer; + DECLARE c cursor for select * from t_cursor; + DECLARE CONTINUE HANDLER for not found + begin + select "before RESIGNAL"; + RESIGNAL SET + MESSAGE_TEXT = "RESIGNAL of not found", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + open c; + fetch c into x; + close c; +end $$ + +--error 5555 +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlexception + begin + select "before RESIGNAL"; + RESIGNAL SET + MESSAGE_TEXT = "RESIGNAL of an error", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + drop table no_such_table; +end $$ + +--error 5555 +call test_resignal() $$ +drop procedure test_resignal $$ + +######################################################### + +# 3 tests: +# {Signaled warning} +# --> RESIGNAL SQLSTATE {warning, not found, error} SET ... + +create procedure test_resignal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01111"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "01222" SET + MESSAGE_TEXT = "RESIGNAL to warning", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL warn SET + MESSAGE_TEXT = "Raising a warning", + MYSQL_ERRNO = 1012; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01111"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "02222" SET + MESSAGE_TEXT = "RESIGNAL to not found", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL warn SET + MESSAGE_TEXT = "Raising a warning", + MYSQL_ERRNO = 1012; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE warn CONDITION FOR SQLSTATE "01111"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "33333" SET + MESSAGE_TEXT = "RESIGNAL to error", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL warn SET + MESSAGE_TEXT = "Raising a warning", + MYSQL_ERRNO = 1012; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +# 3 tests: +# {Signaled not found} +# --> RESIGNAL SQLSTATE {warning, not found, error} SET ... + +create procedure test_resignal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "01222" SET + MESSAGE_TEXT = "RESIGNAL to warning", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL not_found SET + MESSAGE_TEXT = "Raising a not found", + MYSQL_ERRNO = 1012; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "02222" SET + MESSAGE_TEXT = "RESIGNAL to not found", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL not_found SET + MESSAGE_TEXT = "Raising a not found", + MYSQL_ERRNO = 1012; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE not_found CONDITION FOR SQLSTATE "02ABC"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "33333" SET + MESSAGE_TEXT = "RESIGNAL to error", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL not_found SET + MESSAGE_TEXT = "Raising a not found", + MYSQL_ERRNO = 1012; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +# 3 tests: +# {Signaled error} +# --> RESIGNAL SQLSTATE {warning, not found, error} SET ... + +create procedure test_resignal() +begin + DECLARE error CONDITION FOR SQLSTATE "AAAAA"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "01222" SET + MESSAGE_TEXT = "RESIGNAL to warning", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL error SET + MESSAGE_TEXT = "Raising an error", + MYSQL_ERRNO = 1012; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE error CONDITION FOR SQLSTATE "AAAAA"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "02222" SET + MESSAGE_TEXT = "RESIGNAL to not found", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL error SET + MESSAGE_TEXT = "Raising an error", + MYSQL_ERRNO = 1012; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE error CONDITION FOR SQLSTATE "AAAAA"; + DECLARE CONTINUE HANDLER for 1012 + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "33333" SET + MESSAGE_TEXT = "RESIGNAL to error", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + SIGNAL error SET + MESSAGE_TEXT = "Raising an error", + MYSQL_ERRNO = 1012; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +# 3 tests: +# {warning} +# --> RESIGNAL SQLSTATE {warning, not found, error} SET ... + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlwarning + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "01111" SET + MESSAGE_TEXT = "RESIGNAL to a warning", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + insert into t_warn set a= 9999999999999999; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlwarning + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "02444" SET + MESSAGE_TEXT = "RESIGNAL to a not found", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + insert into t_warn set a= 9999999999999999; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlwarning + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "44444" SET + MESSAGE_TEXT = "RESIGNAL to an error", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + insert into t_warn set a= 9999999999999999; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +# 3 tests: +# {not found} +# --> RESIGNAL SQLSTATE {warning, not found, error} SET ... + +create procedure test_resignal() +begin + DECLARE x integer; + DECLARE c cursor for select * from t_cursor; + DECLARE CONTINUE HANDLER for not found + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "01111" SET + MESSAGE_TEXT = "RESIGNAL to a warning", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + open c; + fetch c into x; + close c; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE x integer; + DECLARE c cursor for select * from t_cursor; + DECLARE CONTINUE HANDLER for not found + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "02444" SET + MESSAGE_TEXT = "RESIGNAL to a not found", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + open c; + fetch c into x; + close c; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE x integer; + DECLARE c cursor for select * from t_cursor; + DECLARE CONTINUE HANDLER for not found + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "44444" SET + MESSAGE_TEXT = "RESIGNAL to an error", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + open c; + fetch c into x; + close c; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +# 3 tests: +# {error} +# --> RESIGNAL SQLSTATE {warning, not found, error} SET ... + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlexception + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "01111" SET + MESSAGE_TEXT = "RESIGNAL to a warning", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + drop table no_such_table; +end $$ + +call test_resignal() $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlexception + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "02444" SET + MESSAGE_TEXT = "RESIGNAL to a not found", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + drop table no_such_table; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +create procedure test_resignal() +begin + DECLARE CONTINUE HANDLER for sqlexception + begin + select "before RESIGNAL"; + RESIGNAL SQLSTATE "44444" SET + MESSAGE_TEXT = "RESIGNAL to an error", + MYSQL_ERRNO = 5555 ; + select "after RESIGNAL"; + end; + + drop table no_such_table; +end $$ + +--error 5555 +call test_resignal() $$ +show warnings $$ +drop procedure test_resignal $$ + +--echo # +--echo # More complex cases +--echo # + +--disable_warnings +drop procedure if exists peter_p1 $$ +drop procedure if exists peter_p2 $$ +--enable_warnings + +CREATE PROCEDURE peter_p1 () +BEGIN + DECLARE x CONDITION FOR 1231; + DECLARE EXIT HANDLER FOR x + BEGIN + SELECT '2'; + RESIGNAL SET MYSQL_ERRNO = 9999; + END; + + BEGIN + DECLARE EXIT HANDLER FOR x + BEGIN + SELECT '1'; + RESIGNAL SET SCHEMA_NAME = 'test'; + END; + SET @@sql_mode=NULL; + END; +END +$$ + +CREATE PROCEDURE peter_p2 () +BEGIN + DECLARE x CONDITION for 9999; + DECLARE EXIT HANDLER FOR x + BEGIN + SELECT '3'; + RESIGNAL SET MESSAGE_TEXT = 'Hi, I am a useless error message'; + END; + CALL peter_p1(); +END +$$ + +# +# Here, RESIGNAL only modifies the condition caught, +# so there is only 1 condition at the end +# The final SQLSTATE is 42000 (it comes from the error 1231), +# since the condition attributes are preserved. +# +--error 9999 +CALL peter_p2() $$ +show warnings $$ + +drop procedure peter_p1 $$ +drop procedure peter_p2 $$ + +CREATE PROCEDURE peter_p1 () +BEGIN + DECLARE x CONDITION FOR SQLSTATE '42000'; + DECLARE EXIT HANDLER FOR x + BEGIN + SELECT '2'; + RESIGNAL x SET MYSQL_ERRNO = 9999; + END; + + BEGIN + DECLARE EXIT HANDLER FOR x + BEGIN + SELECT '1'; + RESIGNAL x SET + SCHEMA_NAME = 'test', + MYSQL_ERRNO= 1231; + END; + /* Raises ER_WRONG_VALUE_FOR_VAR : 1231, SQLSTATE 42000 */ + SET @@sql_mode=NULL; + END; +END +$$ + +CREATE PROCEDURE peter_p2 () +BEGIN + DECLARE x CONDITION for SQLSTATE '42000'; + DECLARE EXIT HANDLER FOR x + BEGIN + SELECT '3'; + RESIGNAL x SET + MESSAGE_TEXT = 'Hi, I am a useless error message', + MYSQL_ERRNO = 9999; + END; + CALL peter_p1(); +END +$$ + +# +# Here, "RESIGNAL " create a new condition in the diagnostics +# area, so that there are 4 conditions at the end. +# +--error 9999 +CALL peter_p2() $$ +show warnings $$ + +drop procedure peter_p1 $$ +drop procedure peter_p2 $$ + +# +# Test the value of MESSAGE_TEXT in RESIGNAL when no SET MESSAGE_TEXT clause +# is provided (the expected result is the text from the SIGNALed condition) +# + +drop procedure if exists peter_p3 $$ + +create procedure peter_p3() +begin + declare continue handler for sqlexception + resignal sqlstate '99002' set mysql_errno = 2; + + signal sqlstate '99001' set mysql_errno = 1, message_text = "Original"; +end $$ + +--error 2 +call peter_p3() $$ + +# Expecting 2 conditions, both with the text "Original" +show warnings $$ + +drop procedure peter_p3 $$ + +delimiter ;$$ + +drop table t_warn; +drop table t_cursor; + +--echo # +--echo # Miscelaneous test cases +--echo # + +delimiter $$; + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 0x12; /* 18 */ +end $$ + +-- error 18 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 0b00010010; /* 18 */ +end $$ + +-- error 18 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = '65'; /* 65 */ +end $$ + +-- error 65 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 'A'; /* illegal */ +end $$ + +-- error ER_WRONG_VALUE_FOR_VAR +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = "65"; /* 65 */ +end $$ + +-- error 65 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = "A"; /* illegal */ +end $$ + +-- error ER_WRONG_VALUE_FOR_VAR +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = `65`; /* illegal */ +end $$ + +-- error ER_BAD_FIELD_ERROR +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = `A`; /* illegal */ +end $$ + +-- error ER_BAD_FIELD_ERROR +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 3.141592; /* 3 */ +end $$ + +-- error 3 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 1000, + MESSAGE_TEXT= 0x41; /* A */ +end $$ + +-- error 1000 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 1000, + MESSAGE_TEXT= 0b01000001; /* A */ +end $$ + +-- error 1000 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 1000, + MESSAGE_TEXT = "Hello"; +end $$ + +-- error 1000 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 1000, + MESSAGE_TEXT = 'Hello'; +end $$ + +-- error 1000 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 1000, + MESSAGE_TEXT = `Hello`; +end $$ + +-- error ER_BAD_FIELD_ERROR +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + SIGNAL foo SET MYSQL_ERRNO = 1000, + MESSAGE_TEXT = 65.4321; +end $$ + +-- error 1000 +call test_signal $$ +drop procedure test_signal $$ + +-- error ER_PARSE_ERROR +create procedure test_signal() +begin + DECLARE céèçà foo CONDITION FOR SQLSTATE '12345'; + SIGNAL céèçà SET MYSQL_ERRNO = 1000; +end $$ + +-- error ER_PARSE_ERROR +create procedure test_signal() +begin + DECLARE "céèçà" CONDITION FOR SQLSTATE '12345'; + SIGNAL "céèçà" SET MYSQL_ERRNO = 1000; +end $$ + +-- error ER_PARSE_ERROR +create procedure test_signal() +begin + DECLARE 'céèçà' CONDITION FOR SQLSTATE '12345'; + SIGNAL 'céèçà' SET MYSQL_ERRNO = 1000; +end $$ + +create procedure test_signal() +begin + DECLARE `céèçà` CONDITION FOR SQLSTATE '12345'; + SIGNAL `céèçà` SET MYSQL_ERRNO = 1000; +end $$ + +-- error 1000 +call test_signal $$ +drop procedure test_signal $$ + +create procedure test_signal() +begin + SIGNAL SQLSTATE '77777' SET MYSQL_ERRNO = 1000, MESSAGE_TEXT='ÃÂÃÅÄ'; +end $$ + +# Commented until WL#751 is implemented in this version +# -- error 1000 +# call test_signal $$ +drop procedure test_signal $$ + +delimiter ; $$ + diff --git a/mysql-test/t/signal_code.test b/mysql-test/t/signal_code.test new file mode 100644 index 00000000000..d2f65647c81 --- /dev/null +++ b/mysql-test/t/signal_code.test @@ -0,0 +1,57 @@ +# Copyright (C) 2008 Sun Microsystems, Inc +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Tests for SIGNAL and RESIGNAL + +-- source include/have_debug.inc + +use test; + +--disable_warnings +drop procedure if exists signal_proc; +drop function if exists signal_func; +--enable_warnings + +delimiter $$; + +create procedure signal_proc() +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + + SIGNAL foo; + SIGNAL foo SET MESSAGE_TEXT = "This is an error message"; + RESIGNAL foo; + RESIGNAL foo SET MESSAGE_TEXT = "This is an error message"; +end $$ + +create function signal_func() returns int +begin + DECLARE foo CONDITION FOR SQLSTATE '12345'; + + SIGNAL foo; + SIGNAL foo SET MESSAGE_TEXT = "This is an error message"; + RESIGNAL foo; + RESIGNAL foo SET MESSAGE_TEXT = "This is an error message"; + return 0; +end $$ + +delimiter ;$$ + +show procedure code signal_proc; +drop procedure signal_proc; + +show function code signal_func; +drop function signal_func; + diff --git a/mysql-test/t/signal_demo1.test b/mysql-test/t/signal_demo1.test new file mode 100644 index 00000000000..5de847ba0ba --- /dev/null +++ b/mysql-test/t/signal_demo1.test @@ -0,0 +1,345 @@ +# Copyright (C) 2008 Sun Microsystems, Inc +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# +# Demonstrate how SIGNAL can be used to enforce integrity constraints. +# + +# Naming: +# - PO: Purchase Order +# - AB: Address Book +# - IN: Inventory + +# Simplified schema: +# +# Relation 1: +# PO_ORDER (PK: po_id) 1:1 <---> 0:N (FK: po_id) PO_ORDER_LINE +# +# Relation 2: +# IN_INVENTORY (PK: item_id) 1:1 <---> 0:N (FK: item_id) PO_ORDER_LINE +# +# Relation 3: +# +--> 0:1 (PK: person_id) AB_PHYSICAL_PERSON +# PO_ORDER (FK: cust_id) 1:1 <--| +# +--> 0:1 (PK: company_id) AB_MORAL_PERSON +# This is an 'arc' relationship :) +# + + +--disable_warnings +drop database if exists demo; +--enable_warnings + +create database demo; + +use demo; + +create table ab_physical_person ( + person_id integer, + first_name VARCHAR(50), + middle_initial CHAR, + last_name VARCHAR(50), + primary key (person_id)); + +create table ab_moral_person ( + company_id integer, + name VARCHAR(100), + primary key (company_id)); + +create table in_inventory ( + item_id integer, + descr VARCHAR(50), + stock integer, + primary key (item_id)); + +create table po_order ( + po_id integer auto_increment, + cust_type char, /* arc relationship, see cust_id */ + cust_id integer, /* FK to ab_physical_person *OR* ab_moral_person */ + primary key (po_id)); + +create table po_order_line ( + po_id integer, /* FK to po_order.po_id */ + line_no integer, + item_id integer, /* FK to in_inventory.item_id */ + qty integer); + +delimiter $$; + +--echo # +--echo # Schema integrity enforcement +--echo # + +create procedure check_pk_person(in person_type char, in id integer) +begin + declare x integer; + declare msg varchar(128); + + /* + Test integrity constraints for an 'arc' relationship. + Based on 'person_type', 'id' points to either a + physical person, or a moral person. + */ + case person_type + when 'P' then + begin + select count(person_id) from ab_physical_person + where ab_physical_person.person_id = id + into x; + + if (x != 1) + then + set msg= concat('No such physical person, PK:', id); + SIGNAL SQLSTATE '45000' SET + MESSAGE_TEXT = msg, + MYSQL_ERRNO = 10000; + end if; + end; + + when 'M' then + begin + select count(company_id) from ab_moral_person + where ab_moral_person.company_id = id + into x; + + if (x != 1) + then + set msg= concat('No such moral person, PK:', id); + SIGNAL SQLSTATE '45000' SET + MESSAGE_TEXT = msg, + MYSQL_ERRNO = 10000; + end if; + end; + + else + begin + set msg= concat('No such person type:', person_type); + SIGNAL SQLSTATE '45000' SET + MESSAGE_TEXT = msg, + MYSQL_ERRNO = 20000; + end; + end case; +end +$$ + +create procedure check_pk_inventory(in id integer) +begin + declare x integer; + declare msg varchar(128); + + select count(item_id) from in_inventory + where in_inventory.item_id = id + into x; + + if (x != 1) + then + set msg= concat('Failed integrity constraint, table in_inventory, PK:', + id); + SIGNAL SQLSTATE '45000' SET + MESSAGE_TEXT = msg, + MYSQL_ERRNO = 10000; + end if; +end +$$ + +create procedure check_pk_order(in id integer) +begin + declare x integer; + declare msg varchar(128); + + select count(po_id) from po_order + where po_order.po_id = id + into x; + + if (x != 1) + then + set msg= concat('Failed integrity constraint, table po_order, PK:', id); + SIGNAL SQLSTATE '45000' SET + MESSAGE_TEXT = msg, + MYSQL_ERRNO = 10000; + end if; +end +$$ + +create trigger po_order_bi before insert on po_order +for each row +begin + call check_pk_person(NEW.cust_type, NEW.cust_id); +end +$$ + +create trigger po_order_bu before update on po_order +for each row +begin + call check_pk_person(NEW.cust_type, NEW.cust_id); +end +$$ + +create trigger po_order_line_bi before insert on po_order_line +for each row +begin + call check_pk_order(NEW.po_id); + call check_pk_inventory(NEW.item_id); +end +$$ + +create trigger po_order_line_bu before update on po_order_line +for each row +begin + call check_pk_order(NEW.po_id); + call check_pk_inventory(NEW.item_id); +end +$$ + +--echo # +--echo # Application helpers +--echo # + +create procedure po_create_order( + in p_cust_type char, + in p_cust_id integer, + out id integer) +begin + insert into po_order set cust_type = p_cust_type, cust_id = p_cust_id; + set id = last_insert_id(); +end +$$ + +create procedure po_add_order_line( + in po integer, + in line integer, + in item integer, + in q integer) +begin + insert into po_order_line set + po_id = po, line_no = line, item_id = item, qty = q; +end +$$ + +delimiter ;$$ + +--echo # +--echo # Create sample data +--echo # + +insert into ab_physical_person values + ( 1, "John", "A", "Doe"), + ( 2, "Marry", "B", "Smith") +; + +insert into ab_moral_person values + ( 3, "ACME real estate, INC"), + ( 4, "Local school") +; + +insert into in_inventory values + ( 100, "Table, dinner", 5), + ( 101, "Chair", 20), + ( 200, "Table, coffee", 3), + ( 300, "School table", 25), + ( 301, "School chairs", 50) +; + +select * from ab_physical_person order by person_id; +select * from ab_moral_person order by company_id; +select * from in_inventory order by item_id; + +--echo # +--echo # Entering an order +--echo # + +set @my_po = 0; + +/* John Doe wants 1 table and 4 chairs */ +call po_create_order("P", 1, @my_po); + +call po_add_order_line (@my_po, 1, 100, 1); +call po_add_order_line (@my_po, 2, 101, 4); + +/* Marry Smith wants a coffee table */ +call po_create_order("P", 2, @my_po); + +call po_add_order_line (@my_po, 1, 200, 1); + +--echo # +--echo # Entering bad data in an order +--echo # + +# There is no item 999 in in_inventory +--error 10000 +call po_add_order_line (@my_po, 1, 999, 1); + +--echo # +--echo # Entering bad data in an unknown order +--echo # + +# There is no order 99 in po_order +--error 10000 +call po_add_order_line (99, 1, 100, 1); + +--echo # +--echo # Entering an order for an unknown company +--echo # + +# There is no moral person of id 7 +--error 10000 +call po_create_order("M", 7, @my_po); + +--echo # +--echo # Entering an order for an unknown person type +--echo # + +# There is no person of type X +--error 20000 +call po_create_order("X", 1, @my_po); + +/* The local school wants 10 class tables and 20 chairs */ +call po_create_order("M", 4, @my_po); + +call po_add_order_line (@my_po, 1, 300, 10); +call po_add_order_line (@my_po, 2, 301, 20); + +# Raw data +select * from po_order; +select * from po_order_line; + +# Creative reporting ... + +select po_id as "PO#", + ( case cust_type + when "P" then concat (pp.first_name, + " ", + pp.middle_initial, + " ", + pp.last_name) + when "M" then mp.name + end ) as "Sold to" + from po_order po + left join ab_physical_person pp on po.cust_id = pp.person_id + left join ab_moral_person mp on po.cust_id = company_id +; + +select po_id as "PO#", + ol.line_no as "Line", + ol.item_id as "Item", + inv.descr as "Description", + ol.qty as "Quantity" + from po_order_line ol, in_inventory inv + where inv.item_id = ol.item_id + order by ol.item_id, ol.line_no; + +drop database demo; + + diff --git a/mysql-test/t/signal_demo2.test b/mysql-test/t/signal_demo2.test new file mode 100644 index 00000000000..fc909cb926c --- /dev/null +++ b/mysql-test/t/signal_demo2.test @@ -0,0 +1,207 @@ +# Copyright (C) 2008 Sun Microsystems, Inc +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# +# Demonstrate how RESIGNAL can be used to 'catch' and 're-throw' an error +# + +--disable_warnings +drop database if exists demo; +--enable_warnings + +create database demo; + +use demo; + +delimiter $$; + +create procedure proc_top_a(p1 integer) +begin + ## DECLARE CONTINUE HANDLER for SQLEXCEPTION, NOT FOUND + begin + end; + + select "Starting ..."; + call proc_middle_a(p1); + select "The end"; +end +$$ + +create procedure proc_middle_a(p1 integer) +begin + DECLARE l integer; + # without RESIGNAL: + # Should be: DECLARE EXIT HANDLER for SQLEXCEPTION, NOT FOUND + DECLARE EXIT HANDLER for 1 /* not sure how to handle exceptions */ + begin + select "Oops ... now what ?"; + end; + + select "In prod_middle()"; + + create temporary table t1(a integer, b integer); + select GET_LOCK("user_mutex", 10) into l; + + insert into t1 set a = p1, b = p1; + + call proc_bottom_a(p1); + + select RELEASE_LOCK("user_mutex") into l; + drop temporary table t1; +end +$$ + +create procedure proc_bottom_a(p1 integer) +begin + select "In proc_bottom()"; + + if (p1 = 1) then + begin + select "Doing something that works ..."; + select * from t1; + end; + end if; + + if (p1 = 2) then + begin + select "Doing something that fail (simulate an error) ..."; + drop table no_such_table; + end; + end if; + + if (p1 = 3) then + begin + select "Doing something that *SHOULD* works ..."; + select * from t1; + end; + end if; + +end +$$ + +delimiter ;$$ + +# +# Code without RESIGNAL: +# errors are apparent to the caller, +# but there is no cleanup code, +# so that the environment (get_lock(), temporary table) is polluted ... +# +call proc_top_a(1); + +# Expected +--error ER_BAD_TABLE_ERROR +call proc_top_a(2); + +# Dirty state +--error ER_TABLE_EXISTS_ERROR +call proc_top_a(3); + +# Dirty state +--error ER_TABLE_EXISTS_ERROR +call proc_top_a(1); + +drop temporary table if exists t1; + +delimiter $$; + +create procedure proc_top_b(p1 integer) +begin + select "Starting ..."; + call proc_middle_b(p1); + select "The end"; +end +$$ + +create procedure proc_middle_b(p1 integer) +begin + DECLARE l integer; + DECLARE EXIT HANDLER for SQLEXCEPTION, NOT FOUND + begin + begin + DECLARE CONTINUE HANDLER for SQLEXCEPTION, NOT FOUND + begin + /* Ignore errors from the cleanup code */ + end; + + select "Doing cleanup !"; + select RELEASE_LOCK("user_mutex") into l; + drop temporary table t1; + end; + + RESIGNAL; + end; + + select "In prod_middle()"; + + create temporary table t1(a integer, b integer); + select GET_LOCK("user_mutex", 10) into l; + + insert into t1 set a = p1, b = p1; + + call proc_bottom_b(p1); + + select RELEASE_LOCK("user_mutex") into l; + drop temporary table t1; +end +$$ + +create procedure proc_bottom_b(p1 integer) +begin + select "In proc_bottom()"; + + if (p1 = 1) then + begin + select "Doing something that works ..."; + select * from t1; + end; + end if; + + if (p1 = 2) then + begin + select "Doing something that fail (simulate an error) ..."; + drop table no_such_table; + end; + end if; + + if (p1 = 3) then + begin + select "Doing something that *SHOULD* works ..."; + select * from t1; + end; + end if; + +end +$$ + +delimiter ;$$ + +# +# Code with RESIGNAL: +# errors are apparent to the caller, +# the but cleanup code did get a chance to act ... +# + +call proc_top_b(1); + +--error ER_BAD_TABLE_ERROR +call proc_top_b(2); + +call proc_top_b(3); + +call proc_top_b(1); + +drop database demo; + diff --git a/mysql-test/t/signal_demo3.test b/mysql-test/t/signal_demo3.test new file mode 100644 index 00000000000..347f1b75a79 --- /dev/null +++ b/mysql-test/t/signal_demo3.test @@ -0,0 +1,159 @@ +# Copyright (C) 2008 Sun Microsystems, Inc +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# +# Demonstrate how RESIGNAL can be used to print a stack trace +# + +# Save defaults + +SET @start_global_value = @@global.max_error_count; +SELECT @start_global_value; +SET @start_session_value = @@session.max_error_count; +SELECT @start_session_value; + +--disable_warnings +drop database if exists demo; +--enable_warnings + +create database demo; + +use demo; + +delimiter $$; + +create procedure proc_1() +begin + declare exit handler for sqlexception + resignal sqlstate '45000' set message_text='Oops in proc_1'; + + call proc_2(); +end +$$ + +create procedure proc_2() +begin + declare exit handler for sqlexception + resignal sqlstate '45000' set message_text='Oops in proc_2'; + + call proc_3(); +end +$$ + +create procedure proc_3() +begin + declare exit handler for sqlexception + resignal sqlstate '45000' set message_text='Oops in proc_3'; + + call proc_4(); +end +$$ + +create procedure proc_4() +begin + declare exit handler for sqlexception + resignal sqlstate '45000' set message_text='Oops in proc_4'; + + call proc_5(); +end +$$ + +create procedure proc_5() +begin + declare exit handler for sqlexception + resignal sqlstate '45000' set message_text='Oops in proc_5'; + + call proc_6(); +end +$$ + +create procedure proc_6() +begin + declare exit handler for sqlexception + resignal sqlstate '45000' set message_text='Oops in proc_6'; + + call proc_7(); +end +$$ + +create procedure proc_7() +begin + declare exit handler for sqlexception + resignal sqlstate '45000' set message_text='Oops in proc_7'; + + call proc_8(); +end +$$ + +create procedure proc_8() +begin + declare exit handler for sqlexception + resignal sqlstate '45000' set message_text='Oops in proc_8'; + + call proc_9(); +end +$$ + +create procedure proc_9() +begin + declare exit handler for sqlexception + resignal sqlstate '45000' set message_text='Oops in proc_9'; + + ## Do something that fails, to see how errors are reported + drop table oops_it_is_not_here; +end +$$ + +delimiter ;$$ + +-- error ER_SIGNAL_EXCEPTION +call proc_1(); + +# This is the interesting part: +# the complete call stack from the origin of failure (proc_9) +# to the top level caller (proc_1) is available ... + +show warnings; + +SET @@session.max_error_count = 5; +SELECT @@session.max_error_count; + +-- error ER_SIGNAL_EXCEPTION +call proc_1(); +show warnings; + +SET @@session.max_error_count = 7; +SELECT @@session.max_error_count; + +-- error ER_SIGNAL_EXCEPTION +call proc_1(); +show warnings; + +SET @@session.max_error_count = 9; +SELECT @@session.max_error_count; + +-- error ER_SIGNAL_EXCEPTION +call proc_1(); +show warnings; + +drop database demo; + +# Restore defaults + +SET @@global.max_error_count = @start_global_value; +SELECT @@global.max_error_count; +SET @@session.max_error_count = @start_session_value; +SELECT @@session.max_error_count; + diff --git a/mysql-test/t/signal_sqlmode.test b/mysql-test/t/signal_sqlmode.test new file mode 100644 index 00000000000..860c145a361 --- /dev/null +++ b/mysql-test/t/signal_sqlmode.test @@ -0,0 +1,123 @@ +# Copyright (C) 2008 Sun Microsystems, Inc +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Tests for SIGNAL, RESIGNAL and GET DIAGNOSTICS + +SET @save_sql_mode=@@sql_mode; + +SET sql_mode=''; + +--disable_warnings +drop procedure if exists p; +drop procedure if exists p2; +drop procedure if exists p3; +--enable_warnings + +delimiter $$; + +create procedure p() +begin + declare utf8_var VARCHAR(128) CHARACTER SET UTF8; + set utf8_var = concat(repeat('A', 128), 'X'); + select length(utf8_var), utf8_var; +end +$$ + +create procedure p2() +begin + declare msg VARCHAR(129) CHARACTER SET UTF8; + set msg = concat(repeat('A', 128), 'X'); + select length(msg), msg; + + signal sqlstate '55555' set message_text = msg; +end +$$ + +create procedure p3() +begin + declare name VARCHAR(65) CHARACTER SET UTF8; + set name = concat(repeat('A', 64), 'X'); + select length(name), name; + + signal sqlstate '55555' set + message_text = 'Message', + table_name = name; +end +$$ +delimiter ;$$ + +call p; + +--error ER_SIGNAL_EXCEPTION +call p2; + +--error ER_SIGNAL_EXCEPTION +call p3; + +drop procedure p; +drop procedure p2; +drop procedure p3; + +SET sql_mode='STRICT_ALL_TABLES'; + +delimiter $$; + +create procedure p() +begin + declare utf8_var VARCHAR(128) CHARACTER SET UTF8; + set utf8_var = concat(repeat('A', 128), 'X'); + select length(utf8_var), utf8_var; +end +$$ + +create procedure p2() +begin + declare msg VARCHAR(129) CHARACTER SET UTF8; + set msg = concat(repeat('A', 128), 'X'); + select length(msg), msg; + + signal sqlstate '55555' set message_text = msg; +end +$$ + +create procedure p3() +begin + declare name VARCHAR(65) CHARACTER SET UTF8; + set name = concat(repeat('A', 64), 'X'); + select length(name), name; + + signal sqlstate '55555' set + message_text = 'Message', + table_name = name; +end +$$ + +delimiter ;$$ + +--error ER_DATA_TOO_LONG +call p; + +--error ER_COND_ITEM_TOO_LONG +call p2; + +--error ER_COND_ITEM_TOO_LONG +call p3; + +drop procedure p; +drop procedure p2; +drop procedure p3; + +SET @@sql_mode=@save_sql_mode; + diff --git a/mysys/my_error.c b/mysys/my_error.c index 2cf704d0089..e407e7706fc 100644 --- a/mysys/my_error.c +++ b/mysys/my_error.c @@ -22,7 +22,6 @@ /* Max length of a error message. Should be kept in sync with MYSQL_ERRMSG_SIZE. */ #define ERRMSGSIZE (512) - /* Define some external variables for error handling */ /* @@ -67,12 +66,9 @@ static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs; MyFlags Flags ... variable list - RETURN - What (*error_handler_hook)() returns: - 0 OK */ -int my_error(int nr, myf MyFlags, ...) +void my_error(int nr, myf MyFlags, ...) { const char *format; struct my_err_head *meh_p; @@ -96,7 +92,8 @@ int my_error(int nr, myf MyFlags, ...) (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args); va_end(args); } - DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags)); + (*error_handler_hook)(nr, ebuff, MyFlags); + DBUG_VOID_RETURN; } @@ -111,7 +108,7 @@ int my_error(int nr, myf MyFlags, ...) ... variable list */ -int my_printf_error(uint error, const char *format, myf MyFlags, ...) +void my_printf_error(uint error, const char *format, myf MyFlags, ...) { va_list args; char ebuff[ERRMSGSIZE]; @@ -122,7 +119,8 @@ int my_printf_error(uint error, const char *format, myf MyFlags, ...) va_start(args,MyFlags); (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args); va_end(args); - DBUG_RETURN((*error_handler_hook)(error, ebuff, MyFlags)); + (*error_handler_hook)(error, ebuff, MyFlags); + DBUG_VOID_RETURN; } /* @@ -135,9 +133,9 @@ int my_printf_error(uint error, const char *format, myf MyFlags, ...) MyFlags Flags */ -int my_message(uint error, const char *str, register myf MyFlags) +void my_message(uint error, const char *str, register myf MyFlags) { - return (*error_handler_hook)(error, str, MyFlags); + (*error_handler_hook)(error, str, MyFlags); } diff --git a/mysys/my_messnc.c b/mysys/my_messnc.c index e2431959b7a..e2dee3f6710 100644 --- a/mysys/my_messnc.c +++ b/mysys/my_messnc.c @@ -15,8 +15,8 @@ #include "mysys_priv.h" -int my_message_no_curses(uint error __attribute__((unused)), - const char *str, myf MyFlags) +void my_message_no_curses(uint error __attribute__((unused)), + const char *str, myf MyFlags) { DBUG_ENTER("my_message_no_curses"); DBUG_PRINT("enter",("message: %s",str)); @@ -34,5 +34,5 @@ int my_message_no_curses(uint error __attribute__((unused)), (void)fputs(str,stderr); (void)fputc('\n',stderr); (void)fflush(stderr); - DBUG_RETURN(0); + DBUG_VOID_RETURN; } diff --git a/mysys/my_static.c b/mysys/my_static.c index d0c20da828a..1e7c30992f8 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -87,9 +87,9 @@ ulong my_time_to_wait_for_lock=2; /* In seconds */ char * NEAR globerrs[GLOBERRS]; /* my_error_messages is here */ #endif void (*my_abort_hook)(int) = (void(*)(int)) exit; -int (*error_handler_hook)(uint error,const char *str,myf MyFlags)= +void (*error_handler_hook)(uint error,const char *str,myf MyFlags)= my_message_no_curses; -int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)= +void (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)= my_message_no_curses; #ifdef __WIN__ diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 6f162f4d84d..592092ba7aa 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -75,6 +75,7 @@ SET (SQL_SOURCE rpl_rli.cc rpl_mi.cc sql_servers.cc sql_connect.cc scheduler.cc sql_profile.cc event_parse_data.cc + sql_signal.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h diff --git a/sql/Makefile.am b/sql/Makefile.am index 5263e62a439..600a6117ebf 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -110,7 +110,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ sql_plugin.h authors.h event_parse_data.h \ event_data_objects.h event_scheduler.h \ sql_partition.h partition_info.h partition_element.h \ - contributors.h sql_servers.h + contributors.h sql_servers.h sql_signal.h mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ @@ -154,7 +154,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ event_queue.cc event_db_repository.cc events.cc \ sql_plugin.cc sql_binlog.cc \ sql_builtin.cc sql_tablespace.cc partition_info.cc \ - sql_servers.cc event_parse_data.cc + sql_servers.cc event_parse_data.cc sql_signal.cc nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c diff --git a/sql/authors.h b/sql/authors.h index dfe3b143e2f..bb5156742e5 100644 --- a/sql/authors.h +++ b/sql/authors.h @@ -36,6 +36,7 @@ struct show_table_authors_st { struct show_table_authors_st show_table_authors[]= { { "Brian (Krow) Aker", "Seattle, WA, USA", "Architecture, archive, federated, bunch of little stuff :)" }, + { "Marc Alff", "Denver, CO, USA", "Signal, Resignal" }, { "Venu Anuganti", "", "Client/server protocol (4.1)" }, { "David Axmark", "Uppsala, Sweden", "Small stuff long time ago, Monty ripped it out!" }, diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 8c0025f9ed4..daaa6be0520 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -74,7 +74,7 @@ Event_worker_thread::print_warnings(THD *thd, Event_job_data *et) { MYSQL_ERROR *err; DBUG_ENTER("evex_print_warnings"); - if (!thd->warn_list.elements) + if (thd->warning_info->is_empty()) DBUG_VOID_RETURN; char msg_buf[10 * STRING_BUFFER_USUAL_SIZE]; @@ -90,17 +90,18 @@ Event_worker_thread::print_warnings(THD *thd, Event_job_data *et) prefix.append(et->name.str, et->name.length, system_charset_info); prefix.append("] ", 2); - List_iterator_fast it(thd->warn_list); + List_iterator_fast it(thd->warning_info->warn_list()); while ((err= it++)) { String err_msg(msg_buf, sizeof(msg_buf), system_charset_info); /* set it to 0 or we start adding at the end. That's the trick ;) */ err_msg.length(0); err_msg.append(prefix); - err_msg.append(err->msg, strlen(err->msg), system_charset_info); - DBUG_ASSERT(err->level < 3); - (sql_print_message_handlers[err->level])("%*s", err_msg.length(), - err_msg.c_ptr()); + err_msg.append(err->get_message_text(), + err->get_message_octet_length(), system_charset_info); + DBUG_ASSERT(err->get_level() < 3); + (sql_print_message_handlers[err->get_level()])("%*s", err_msg.length(), + err_msg.c_ptr()); } DBUG_VOID_RETURN; } diff --git a/sql/field.cc b/sql/field.cc index 426effa57cd..5ca3b829d69 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1116,7 +1116,7 @@ int Field_num::check_int(CHARSET_INFO *cs, const char *str, int length, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), "integer", tmp.c_ptr(), field_name, - (ulong) table->in_use->row_count); + (ulong) table->in_use->warning_info->current_row_for_warning()); return 1; } /* Test if we have garbage at the end of the given string. */ @@ -2683,11 +2683,11 @@ int Field_new_decimal::store(const char *from, uint length, String from_as_str; from_as_str.copy(from, length, &my_charset_bin); - push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), "decimal", from_as_str.c_ptr(), field_name, - (ulong) table->in_use->row_count); + (ulong) table->in_use->warning_info->current_row_for_warning()); DBUG_RETURN(err); } @@ -2710,7 +2710,7 @@ int Field_new_decimal::store(const char *from, uint length, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), "decimal", from_as_str.c_ptr(), field_name, - (ulong) table->in_use->row_count); + (ulong) table->in_use->warning_info->current_row_for_warning()); my_decimal_set_zero(&decimal_value); break; @@ -5363,7 +5363,7 @@ bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, ER(ER_WARN_DATA_OUT_OF_RANGE), field_name, - thd->row_count); + thd->warning_info->current_row_for_warning()); return 1; } tmp=(long) sint3korr(ptr); @@ -6357,21 +6357,20 @@ check_string_copy_error(Field_str *field, { const char *pos; char tmp[32]; - + THD *thd= field->table->in_use; + if (!(pos= well_formed_error_pos) && !(pos= cannot_convert_error_pos)) return FALSE; convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6); - push_warning_printf(field->table->in_use, - field->table->in_use->abort_on_warning ? - MYSQL_ERROR::WARN_LEVEL_ERROR : + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), "string", tmp, field->field_name, - (ulong) field->table->in_use->row_count); + thd->warning_info->current_row_for_warning()); return TRUE; } @@ -6405,7 +6404,7 @@ Field_longstr::report_if_important_data(const char *ptr, const char *end, if (test_if_important_data(field_charset, ptr, end)) { if (table->in_use->abort_on_warning) - set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); else set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); return 2; @@ -9035,7 +9034,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs) set_rec_bits((1 << bit_len) - 1, bit_ptr, bit_ofs, bit_len); memset(ptr, 0xff, bytes_in_rec); if (table->in_use->really_abort_on_warning()) - set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); else set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; @@ -9446,7 +9445,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs) if (bits) *ptr&= ((1 << bits) - 1); /* set first uchar */ if (table->in_use->really_abort_on_warning()) - set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); else set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; @@ -10321,7 +10320,7 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code, { thd->cuted_fields+= cuted_increment; push_warning_printf(thd, level, code, ER(code), field_name, - thd->row_count); + thd->warning_info->current_row_for_warning()); return 0; } return level >= MYSQL_ERROR::WARN_LEVEL_WARN; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 264e5649ea9..90194fa00e7 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -265,11 +265,11 @@ static int ndb_to_mysql_error(const NdbError *ndberr) - Used by replication to see if the error was temporary */ if (ndberr->status == NdbError::TemporaryError) - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_TEMPORARY_ERRMSG, ER(ER_GET_TEMPORARY_ERRMSG), ndberr->code, ndberr->message, "NDB"); else - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), ndberr->code, ndberr->message, "NDB"); return error; @@ -536,7 +536,7 @@ static void set_ndb_err(THD *thd, const NdbError &err) { char buf[FN_REFLEN]; ndb_error_string(thd_ndb->m_error_code, buf, sizeof(buf)); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), thd_ndb->m_error_code, buf, "NDB"); } @@ -5308,7 +5308,7 @@ int ha_ndbcluster::create(const char *name, { if (create_info->storage_media == HA_SM_MEMORY) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, ER(ER_ILLEGAL_HA_CREATE_OPTION), ndbcluster_hton_name, @@ -5363,7 +5363,7 @@ int ha_ndbcluster::create(const char *name, case ROW_TYPE_FIXED: if (field_type_forces_var_part(field->type())) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, ER(ER_ILLEGAL_HA_CREATE_OPTION), ndbcluster_hton_name, @@ -5703,7 +5703,7 @@ int ha_ndbcluster::create_index(const char *name, KEY *key_info, case ORDERED_INDEX: if (key_info->algorithm == HA_KEY_ALG_HASH) { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, ER(ER_ILLEGAL_HA_CREATE_OPTION), ndbcluster_hton_name, @@ -9606,11 +9606,11 @@ char* ha_ndbcluster::get_tablespace_name(THD *thd, char* name, uint name_len) } err: if (ndberr.status == NdbError::TemporaryError) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_TEMPORARY_ERRMSG, ER(ER_GET_TEMPORARY_ERRMSG), ndberr.code, ndberr.message, "NDB"); else - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), ndberr.code, ndberr.message, "NDB"); return 0; @@ -9904,7 +9904,7 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info, { if (!current_thd->variables.new_mode) { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, ER(ER_ILLEGAL_HA_CREATE_OPTION), ndbcluster_hton_name, diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index d9a9738ce72..b9b9e7acbf2 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -272,13 +272,13 @@ static void run_query(THD *thd, char *buf, char *end, Thd_ndb *thd_ndb= get_thd_ndb(thd); for (i= 0; no_print_error[i]; i++) if ((thd_ndb->m_error_code == no_print_error[i]) || - (thd->main_da.sql_errno() == (unsigned) no_print_error[i])) + (thd->stmt_da->sql_errno() == (unsigned) no_print_error[i])) break; if (!no_print_error[i]) sql_print_error("NDB: %s: error %s %d(ndb: %d) %d %d", buf, - thd->main_da.message(), - thd->main_da.sql_errno(), + thd->stmt_da->message(), + thd->stmt_da->sql_errno(), thd_ndb->m_error_code, (int) thd->is_error(), thd->is_slave_error); } @@ -293,7 +293,7 @@ static void run_query(THD *thd, char *buf, char *end, is called from ndbcluster_reset_logs(), which is called from mysql_flush(). */ - thd->main_da.reset_diagnostics_area(); + thd->stmt_da->reset_diagnostics_area(); thd->options= save_thd_options; thd->set_query(save_thd_query, save_thd_query_length); @@ -963,6 +963,21 @@ struct Cluster_schema uint32 any_value; }; +static void print_could_not_discover_error(THD *thd, + const Cluster_schema *schema) +{ + sql_print_error("NDB Binlog: Could not discover table '%s.%s' from " + "binlog schema event '%s' from node %d. " + "my_errno: %d", + schema->db, schema->name, schema->query, + schema->node_id, my_errno); + List_iterator_fast it(thd->warning_info->warn_list()); + MYSQL_ERROR *err; + while ((err= it++)) + sql_print_warning("NDB Binlog: (%d)%s", err->get_sql_errno(), + err->get_message_text()); +} + /* Transfer schema table data into corresponding struct */ @@ -1198,7 +1213,7 @@ ndbcluster_update_slock(THD *thd, } if (ndb_error) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), ndb_error->code, ndb_error->message, @@ -1521,7 +1536,7 @@ err: } end: if (ndb_error) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), ndb_error->code, ndb_error->message, @@ -1971,15 +1986,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, } else if (ndb_create_table_from_engine(thd, schema->db, schema->name)) { - sql_print_error("NDB Binlog: Could not discover table '%s.%s' from " - "binlog schema event '%s' from node %d. " - "my_errno: %d", - schema->db, schema->name, schema->query, - schema->node_id, my_errno); - List_iterator_fast it(thd->warn_list); - MYSQL_ERROR *err; - while ((err= it++)) - sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg); + print_could_not_discover_error(thd, schema); } pthread_mutex_unlock(&LOCK_open); log_query= 1; @@ -2262,14 +2269,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd, } else if (ndb_create_table_from_engine(thd, schema->db, schema->name)) { - sql_print_error("NDB Binlog: Could not discover table '%s.%s' from " - "binlog schema event '%s' from node %d. my_errno: %d", - schema->db, schema->name, schema->query, - schema->node_id, my_errno); - List_iterator_fast it(thd->warn_list); - MYSQL_ERROR *err; - while ((err= it++)) - sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg); + print_could_not_discover_error(thd, schema); } pthread_mutex_unlock(&LOCK_open); } @@ -2344,8 +2344,8 @@ static int open_ndb_binlog_index(THD *thd, TABLE_LIST *tables, sql_print_error("NDB Binlog: Opening ndb_binlog_index: killed"); else sql_print_error("NDB Binlog: Opening ndb_binlog_index: %d, '%s'", - thd->main_da.sql_errno(), - thd->main_da.message()); + thd->stmt_da->sql_errno(), + thd->stmt_da->message()); thd->proc_info= save_proc_info; return -1; } @@ -2741,7 +2741,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab, "with BLOB attribute and no PK is not supported", share->key); if (push_warning) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, ER(ER_ILLEGAL_HA_CREATE_OPTION), ndbcluster_hton_name, @@ -2785,7 +2785,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab, failed, print a warning */ if (push_warning > 1) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), dict->getNdbError().code, dict->getNdbError().message, "NDB"); @@ -2813,7 +2813,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab, dict->dropEvent(my_event.getName())) { if (push_warning > 1) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), dict->getNdbError().code, dict->getNdbError().message, "NDB"); @@ -2832,7 +2832,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab, if (dict->createEvent(my_event)) { if (push_warning > 1) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), dict->getNdbError().code, dict->getNdbError().message, "NDB"); @@ -2845,7 +2845,7 @@ ndbcluster_create_event(Ndb *ndb, const NDBTAB *ndbtab, DBUG_RETURN(-1); } #ifdef NDB_BINLOG_EXTRA_WARNINGS - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), 0, "NDB Binlog: Removed trailing event", "NDB"); @@ -2956,7 +2956,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, { sql_print_error("NDB Binlog: Creating NdbEventOperation failed for" " %s",event_name); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), ndb->getNdbError().code, ndb->getNdbError().message, @@ -3005,7 +3005,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, sql_print_error("NDB Binlog: Creating NdbEventOperation" " blob field %u handles failed (code=%d) for %s", j, op->getNdbError().code, event_name); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), op->getNdbError().code, op->getNdbError().message, @@ -3044,7 +3044,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab, retries= 0; if (retries == 0) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), op->getNdbError().code, op->getNdbError().message, "NDB"); @@ -3112,7 +3112,7 @@ ndbcluster_handle_drop_table(Ndb *ndb, const char *event_name, if (dict->getNdbError().code != 4710) { /* drop event failed for some reason, issue a warning */ - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_GET_ERRMSG, ER(ER_GET_ERRMSG), dict->getNdbError().code, dict->getNdbError().message, "NDB"); diff --git a/sql/handler.cc b/sql/handler.cc index 0e83d2911f2..c29cb196b60 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1313,7 +1313,7 @@ int ha_rollback_trans(THD *thd, bool all) trans->ha_list= 0; trans->no_2pc=0; if (is_real_trans && thd->transaction_rollback_request) - thd->transaction.xid_state.rm_error= thd->main_da.sql_errno(); + thd->transaction.xid_state.rm_error= thd->stmt_da->sql_errno(); if (all) thd->variables.tx_isolation=thd->session_tx_isolation; } @@ -1914,23 +1914,28 @@ const char *get_canonical_filename(handler *file, const char *path, struct Ha_delete_table_error_handler: public Internal_error_handler { public: - virtual bool handle_error(uint sql_errno, - const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd); + 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); char buff[MYSQL_ERRMSG_SIZE]; }; bool Ha_delete_table_error_handler:: -handle_error(uint sql_errno, - const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd) +handle_condition(THD *, + uint, + const char*, + MYSQL_ERROR::enum_warning_level, + const char* msg, + MYSQL_ERROR ** cond_hdl) { + *cond_hdl= NULL; /* Grab the error message */ - strmake(buff, message, sizeof(buff)-1); + strmake(buff, msg, sizeof(buff)-1); return TRUE; } @@ -1989,7 +1994,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, XXX: should we convert *all* errors to warnings here? What if the error is fatal? */ - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, error, ha_delete_table_error_handler.buff); } delete file; diff --git a/sql/item.cc b/sql/item.cc index 9551c5feaff..6a92016e1ec 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4785,7 +4785,6 @@ String *Item::check_well_formed_result(String *str, bool send_error) { THD *thd= current_thd; char hexbuf[7]; - enum MYSQL_ERROR::enum_warning_level level; uint diff= str->length() - wlen; set_if_smaller(diff, 3); octet2hex(hexbuf, str->ptr() + wlen, diff); @@ -4798,16 +4797,14 @@ String *Item::check_well_formed_result(String *str, bool send_error) if ((thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))) { - level= MYSQL_ERROR::WARN_LEVEL_ERROR; null_value= 1; str= 0; } else { - level= MYSQL_ERROR::WARN_LEVEL_WARN; str->length(wlen); } - push_warning_printf(thd, level, ER_INVALID_CHARACTER_STRING, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_INVALID_CHARACTER_STRING, ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf); } return str; diff --git a/sql/item_func.cc b/sql/item_func.cc index 6abc78371db..5d91c8ab97c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -599,7 +599,7 @@ void Item_func::signal_divide_by_null() { THD *thd= current_thd; if (thd->variables.sql_mode & MODE_ERROR_FOR_DIVISION_BY_ZERO) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DIVISION_BY_ZERO, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO)); null_value= 1; } @@ -1054,7 +1054,7 @@ my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec) return dec; err: - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, ER(ER_WARN_DATA_OUT_OF_RANGE), name, 1); @@ -3670,7 +3670,7 @@ longlong Item_func_benchmark::val_int() { char buff[22]; llstr(((longlong) loop_count), buff); - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE), "count", buff, "benchmark"); } @@ -5814,12 +5814,12 @@ Item_func_sp::func_name() const } -int my_missing_function_error(const LEX_STRING &token, const char *func_name) +void my_missing_function_error(const LEX_STRING &token, const char *func_name) { if (token.length && is_lex_native_function (&token)) - return my_error(ER_FUNC_INEXISTENT_NAME_COLLISION, MYF(0), func_name); + my_error(ER_FUNC_INEXISTENT_NAME_COLLISION, MYF(0), func_name); else - return my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", func_name); + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", func_name); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index be94f19f597..25c9539c4a5 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -528,11 +528,11 @@ String *Item_func_des_encrypt::val_str(String *str) return &tmp_value; error: - push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN, code, ER(code), "des_encrypt"); #else - push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN, ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED), "des_encrypt","--with-openssl"); #endif /* HAVE_OPENSSL */ @@ -605,12 +605,12 @@ String *Item_func_des_decrypt::val_str(String *str) return &tmp_value; error: - push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN, code, ER(code), "des_decrypt"); wrong_key: #else - push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN, ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED), "des_decrypt","--with-openssl"); #endif /* HAVE_OPENSSL */ @@ -3232,7 +3232,7 @@ longlong Item_func_uncompressed_length::val_int() */ if (res->length() <= 4) { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ZLIB_Z_DATA_ERROR, ER(ER_ZLIB_Z_DATA_ERROR)); null_value= 1; @@ -3309,7 +3309,7 @@ String *Item_func_compress::val_str(String *str) (const Bytef*)res->ptr(), res->length())) != Z_OK) { code= err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_BUF_ERROR; - push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code)); + push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,code,ER(code)); null_value= 1; return 0; } @@ -3347,7 +3347,7 @@ String *Item_func_uncompress::val_str(String *str) /* If length is less than 4 bytes, data is corrupt */ if (res->length() <= 4) { - push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN, ER_ZLIB_Z_DATA_ERROR, ER(ER_ZLIB_Z_DATA_ERROR)); goto err; @@ -3357,7 +3357,7 @@ String *Item_func_uncompress::val_str(String *str) new_size= uint4korr(res->ptr()) & 0x3FFFFFFF; if (new_size > current_thd->variables.max_allowed_packet) { - push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN, ER_TOO_BIG_FOR_UNCOMPRESS, ER(ER_TOO_BIG_FOR_UNCOMPRESS), current_thd->variables.max_allowed_packet); @@ -3375,7 +3375,7 @@ String *Item_func_uncompress::val_str(String *str) code= ((err == Z_BUF_ERROR) ? ER_ZLIB_Z_BUF_ERROR : ((err == Z_MEM_ERROR) ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_DATA_ERROR)); - push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code)); + push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_WARN,code,ER(code)); err: null_value= 1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 08a48c6ce2f..ceb553f1c8a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3102,6 +3102,8 @@ int dump_leaf_key(uchar* key, element_count count __attribute__((unused)), result->append(*res); } + item->row_count++; + /* stop if length of result more than max_length */ if (result->length() > item->max_length) { @@ -3120,8 +3122,11 @@ int dump_leaf_key(uchar* key, element_count count __attribute__((unused)), result->length(), &well_formed_error); result->length(old_length + add_length); - item->count_cut_values++; item->warning_for_row= TRUE; + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CUT_VALUE_GROUP_CONCAT, ER(ER_CUT_VALUE_GROUP_CONCAT), + item->row_count); + return 1; } return 0; @@ -3141,12 +3146,12 @@ Item_func_group_concat:: Item_func_group_concat(Name_resolution_context *context_arg, bool distinct_arg, List *select_list, SQL_LIST *order_list, String *separator_arg) - :tmp_table_param(0), warning(0), - separator(separator_arg), tree(0), unique_filter(NULL), table(0), + :tmp_table_param(0), separator(separator_arg), tree(0), + unique_filter(NULL), table(0), order(0), context(context_arg), arg_count_order(order_list ? order_list->elements : 0), arg_count_field(select_list->elements), - count_cut_values(0), + row_count(0), distinct(distinct_arg), warning_for_row(FALSE), force_copy_fields(0), original(0) @@ -3200,7 +3205,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, Item_func_group_concat *item) :Item_sum(thd, item), tmp_table_param(item->tmp_table_param), - warning(item->warning), separator(item->separator), tree(item->tree), unique_filter(item->unique_filter), @@ -3209,7 +3213,7 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, context(item->context), arg_count_order(item->arg_count_order), arg_count_field(item->arg_count_field), - count_cut_values(item->count_cut_values), + row_count(item->row_count), distinct(item->distinct), warning_for_row(item->warning_for_row), always_null(item->always_null), @@ -3227,15 +3231,6 @@ void Item_func_group_concat::cleanup() DBUG_ENTER("Item_func_group_concat::cleanup"); Item_sum::cleanup(); - /* Adjust warning message to include total number of cut values */ - if (warning) - { - char warn_buff[MYSQL_ERRMSG_SIZE]; - sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values); - warning->set_msg(current_thd, warn_buff); - warning= 0; - } - /* Free table and tree if they belong to this item (if item have not pointer to original item from which was made copy => it own its objects ) @@ -3259,15 +3254,8 @@ void Item_func_group_concat::cleanup() delete unique_filter; unique_filter= NULL; } - if (warning) - { - char warn_buff[MYSQL_ERRMSG_SIZE]; - sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values); - warning->set_msg(thd, warn_buff); - warning= 0; - } } - DBUG_ASSERT(tree == 0 && warning == 0); + DBUG_ASSERT(tree == 0); } DBUG_VOID_RETURN; } @@ -3556,17 +3544,6 @@ String* Item_func_group_concat::val_str(String* str) /* Tree is used for sorting as in ORDER BY */ tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this, left_root_right); - if (count_cut_values && !warning) - { - /* - ER_CUT_VALUE_GROUP_CONCAT needs an argument, but this gets set in - Item_func_group_concat::cleanup(). - */ - DBUG_ASSERT(table); - warning= push_warning(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_CUT_VALUE_GROUP_CONCAT, - ER(ER_CUT_VALUE_GROUP_CONCAT)); - } return &result; } diff --git a/sql/item_sum.h b/sql/item_sum.h index d991327d847..8a20e2dd165 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1181,12 +1181,9 @@ public: #endif /* HAVE_DLOPEN */ -class MYSQL_ERROR; - class Item_func_group_concat : public Item_sum { TMP_TABLE_PARAM *tmp_table_param; - MYSQL_ERROR *warning; String result; String *separator; TREE tree_base; @@ -1207,7 +1204,7 @@ class Item_func_group_concat : public Item_sum uint arg_count_order; /** The number of selected items, aka the expr list. */ uint arg_count_field; - uint count_cut_values; + uint row_count; bool distinct; bool warning_for_row; bool always_null; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d79b0b02998..fe938426863 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -602,7 +602,7 @@ err: { char buff[128]; strmake(buff, val_begin, min(length, sizeof(buff)-1)); - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE), date_time_type, buff, "str_to_date"); } diff --git a/sql/lex.h b/sql/lex.h index 0a85824f6f7..268c77a4f98 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -96,6 +96,7 @@ static SYMBOL symbols[] = { { "CASCADE", SYM(CASCADE)}, { "CASCADED", SYM(CASCADED)}, { "CASE", SYM(CASE_SYM)}, + { "CATALOG_NAME", SYM(CATALOG_NAME_SYM)}, { "CHAIN", SYM(CHAIN_SYM)}, { "CHANGE", SYM(CHANGE)}, { "CHANGED", SYM(CHANGED)}, @@ -105,6 +106,7 @@ static SYMBOL symbols[] = { { "CHECK", SYM(CHECK_SYM)}, { "CHECKSUM", SYM(CHECKSUM_SYM)}, { "CIPHER", SYM(CIPHER_SYM)}, + { "CLASS_ORIGIN", SYM(CLASS_ORIGIN_SYM)}, { "CLIENT", SYM(CLIENT_SYM)}, { "CLOSE", SYM(CLOSE_SYM)}, { "COALESCE", SYM(COALESCE)}, @@ -112,6 +114,7 @@ static SYMBOL symbols[] = { { "COLLATE", SYM(COLLATE_SYM)}, { "COLLATION", SYM(COLLATION_SYM)}, { "COLUMN", SYM(COLUMN_SYM)}, + { "COLUMN_NAME", SYM(COLUMN_NAME_SYM)}, { "COLUMNS", SYM(COLUMNS)}, { "COMMENT", SYM(COMMENT_SYM)}, { "COMMIT", SYM(COMMIT_SYM)}, @@ -124,6 +127,9 @@ static SYMBOL symbols[] = { { "CONNECTION", SYM(CONNECTION_SYM)}, { "CONSISTENT", SYM(CONSISTENT_SYM)}, { "CONSTRAINT", SYM(CONSTRAINT)}, + { "CONSTRAINT_CATALOG", SYM(CONSTRAINT_CATALOG_SYM)}, + { "CONSTRAINT_NAME", SYM(CONSTRAINT_NAME_SYM)}, + { "CONSTRAINT_SCHEMA", SYM(CONSTRAINT_SCHEMA_SYM)}, { "CONTAINS", SYM(CONTAINS_SYM)}, { "CONTEXT", SYM(CONTEXT_SYM)}, { "CONTINUE", SYM(CONTINUE_SYM)}, @@ -138,6 +144,7 @@ static SYMBOL symbols[] = { { "CURRENT_TIMESTAMP", SYM(NOW_SYM)}, { "CURRENT_USER", SYM(CURRENT_USER)}, { "CURSOR", SYM(CURSOR_SYM)}, + { "CURSOR_NAME", SYM(CURSOR_NAME_SYM)}, { "DATA", SYM(DATA_SYM)}, { "DATABASE", SYM(DATABASE)}, { "DATABASES", SYM(DATABASES)}, @@ -334,6 +341,7 @@ static SYMBOL symbols[] = { { "MEDIUMTEXT", SYM(MEDIUMTEXT)}, { "MEMORY", SYM(MEMORY_SYM)}, { "MERGE", SYM(MERGE_SYM)}, + { "MESSAGE_TEXT", SYM(MESSAGE_TEXT_SYM)}, { "MICROSECOND", SYM(MICROSECOND_SYM)}, { "MIDDLEINT", SYM(MEDIUMINT)}, /* For powerbuilder */ { "MIGRATE", SYM(MIGRATE_SYM)}, @@ -350,6 +358,7 @@ static SYMBOL symbols[] = { { "MULTIPOINT", SYM(MULTIPOINT)}, { "MULTIPOLYGON", SYM(MULTIPOLYGON)}, { "MUTEX", SYM(MUTEX_SYM)}, + { "MYSQL_ERRNO", SYM(MYSQL_ERRNO_SYM)}, { "NAME", SYM(NAME_SYM)}, { "NAMES", SYM(NAMES_SYM)}, { "NATIONAL", SYM(NATIONAL_SYM)}, @@ -441,6 +450,7 @@ static SYMBOL symbols[] = { { "REPEAT", SYM(REPEAT_SYM)}, { "REQUIRE", SYM(REQUIRE_SYM)}, { "RESET", SYM(RESET_SYM)}, + { "RESIGNAL", SYM(RESIGNAL_SYM)}, { "RESTORE", SYM(RESTORE_SYM)}, { "RESTRICT", SYM(RESTRICT)}, { "RESUME", SYM(RESUME_SYM)}, @@ -459,6 +469,7 @@ static SYMBOL symbols[] = { { "SAVEPOINT", SYM(SAVEPOINT_SYM)}, { "SCHEDULE", SYM(SCHEDULE_SYM)}, { "SCHEMA", SYM(DATABASE)}, + { "SCHEMA_NAME", SYM(SCHEMA_NAME_SYM)}, { "SCHEMAS", SYM(DATABASES)}, { "SECOND", SYM(SECOND_SYM)}, { "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM)}, @@ -474,6 +485,7 @@ static SYMBOL symbols[] = { { "SHARE", SYM(SHARE_SYM)}, { "SHOW", SYM(SHOW)}, { "SHUTDOWN", SYM(SHUTDOWN)}, + { "SIGNAL", SYM(SIGNAL_SYM)}, { "SIGNED", SYM(SIGNED_SYM)}, { "SIMPLE", SYM(SIMPLE_SYM)}, { "SLAVE", SYM(SLAVE)}, @@ -515,6 +527,7 @@ static SYMBOL symbols[] = { { "STORAGE", SYM(STORAGE_SYM)}, { "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN)}, { "STRING", SYM(STRING_SYM)}, + { "SUBCLASS_ORIGIN", SYM(SUBCLASS_ORIGIN_SYM)}, { "SUBJECT", SYM(SUBJECT_SYM)}, { "SUBPARTITION", SYM(SUBPARTITION_SYM)}, { "SUBPARTITIONS", SYM(SUBPARTITIONS_SYM)}, @@ -523,6 +536,7 @@ static SYMBOL symbols[] = { { "SWAPS", SYM(SWAPS_SYM)}, { "SWITCHES", SYM(SWITCHES_SYM)}, { "TABLE", SYM(TABLE_SYM)}, + { "TABLE_NAME", SYM(TABLE_NAME_SYM)}, { "TABLES", SYM(TABLES)}, { "TABLESPACE", SYM(TABLESPACE)}, { "TABLE_CHECKSUM", SYM(TABLE_CHECKSUM_SYM)}, diff --git a/sql/log.cc b/sql/log.cc index bb81d0c723e..fd2b686fb50 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -80,23 +80,28 @@ public: virtual ~Silence_log_table_errors() {} - virtual bool handle_error(uint sql_errno, const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd); + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sql_state, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl); const char *message() const { return m_message; } }; bool -Silence_log_table_errors::handle_error(uint /* sql_errno */, - const char *message_arg, - MYSQL_ERROR::enum_warning_level /* level */, - THD * /* thd */) +Silence_log_table_errors::handle_condition(THD *, + uint, + const char*, + MYSQL_ERROR::enum_warning_level, + const char* msg, + MYSQL_ERROR ** cond_hdl) { - strmake(m_message, message_arg, sizeof(m_message)-1); + *cond_hdl= NULL; + strmake(m_message, msg, sizeof(m_message)-1); return TRUE; } - sql_print_message_func sql_print_message_handlers[3] = { sql_print_information, @@ -1646,7 +1651,7 @@ bool MYSQL_BIN_LOG::check_write_error(THD *thd) if (!thd->is_error()) DBUG_RETURN(checked); - switch (thd->main_da.sql_errno()) + switch (thd->stmt_da->sql_errno()) { case ER_TRANS_CACHE_FULL: case ER_ERROR_ON_WRITE: @@ -2902,7 +2907,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) } else { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_BINLOG_PURGE_FATAL_ERR, "a problem with deleting %s; " "consider examining correspondence " @@ -2933,7 +2938,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) } else { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_BINLOG_PURGE_FATAL_ERR, "a problem with deleting %s; " "consider examining correspondence " @@ -3264,7 +3269,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, */ if (thd) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_BINLOG_PURGE_FATAL_ERR, "a problem with getting info on being purged %s; " "consider examining correspondence " @@ -3310,7 +3315,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, { if (thd) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_BINLOG_PURGE_FATAL_ERR, "a problem with deleting %s; " "consider examining correspondence " @@ -3409,7 +3414,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) */ if (thd) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_BINLOG_PURGE_FATAL_ERR, "a problem with getting info on being purged %s; " "consider examining correspondence " @@ -4419,9 +4424,9 @@ int query_error_code(THD *thd, bool not_killed) if (not_killed) { - error= thd->is_error() ? thd->main_da.sql_errno() : 0; + error= thd->is_error() ? thd->stmt_da->sql_errno() : 0; - /* thd->main_da.sql_errno() might be ER_SERVER_SHUTDOWN or + /* thd->stmt_da->sql_errno() might be ER_SERVER_SHUTDOWN or ER_QUERY_INTERRUPTED, So here we need to make sure that error is not set to these errors when specified not_killed by the caller. diff --git a/sql/log_event.cc b/sql/log_event.cc index 375f9cf1859..a19c5929d7d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -134,7 +134,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, char buff[MAX_SLAVE_ERRMSG], *slider; const char *buff_end= buff + sizeof(buff); uint len; - List_iterator_fast it(thd->warn_list); + List_iterator_fast it(thd->warning_info->warn_list()); MYSQL_ERROR *err; buff[0]= 0; @@ -142,10 +142,11 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, slider += len, err= it++) { len= my_snprintf(slider, buff_end - slider, - " %s, Error_code: %d;", err->msg, err->code); + " %s, Error_code: %d;", err->get_message_text(), + err->get_sql_errno()); } - rli->report(level, thd->is_error()? thd->main_da.sql_errno() : 0, + rli->report(level, thd->is_error()? thd->stmt_da->sql_errno() : 0, "Could not execute %s event on table %s.%s;" "%s handler error %s; " "the event's master log %s, end_log_pos %lu", @@ -353,13 +354,13 @@ inline int ignored_error_code(int err_code) */ int convert_handler_error(int error, THD* thd, TABLE *table) { - uint actual_error= (thd->is_error() ? thd->main_da.sql_errno() : + uint actual_error= (thd->is_error() ? thd->stmt_da->sql_errno() : 0); if (actual_error == 0) { table->file->print_error(error, MYF(0)); - actual_error= (thd->is_error() ? thd->main_da.sql_errno() : + actual_error= (thd->is_error() ? thd->stmt_da->sql_errno() : ER_UNKNOWN_ERROR); if (actual_error == ER_UNKNOWN_ERROR) if (global_system_variables.log_warnings) @@ -3162,7 +3163,7 @@ START SLAVE; . Query: '%s'", expected_error, thd->query); } /* If the query was not ignored, it is printed to the general log */ - if (!thd->is_error() || thd->main_da.sql_errno() != ER_SLAVE_IGNORED_TABLE) + if (!thd->is_error() || thd->stmt_da->sql_errno() != ER_SLAVE_IGNORED_TABLE) general_log_write(thd, COM_QUERY, thd->query, thd->query_length); compare_errors: @@ -3171,7 +3172,7 @@ compare_errors: If we expected a non-zero error code, and we don't get the same error code, and it should be ignored or is related to a concurrency issue. */ - actual_error= thd->is_error() ? thd->main_da.sql_errno() : 0; + actual_error= thd->is_error() ? thd->stmt_da->sql_errno() : 0; DBUG_PRINT("info",("expected_error: %d sql_errno: %d", expected_error, actual_error)); if ((expected_error && expected_error != actual_error && @@ -3186,7 +3187,7 @@ Error on master: '%s' (%d), Error on slave: '%s' (%d). \ Default database: '%s'. Query: '%s'", ER_SAFE(expected_error), expected_error, - actual_error ? thd->main_da.message() : "no error", + actual_error ? thd->stmt_da->message() : "no error", actual_error, print_slave_db_safe(db), query_arg); thd->is_slave_error= 1; @@ -3218,7 +3219,7 @@ Default database: '%s'. Query: '%s'", { rli->report(ERROR_LEVEL, actual_error, "Error '%s' on query. Default database: '%s'. Query: '%s'", - (actual_error ? thd->main_da.message() : + (actual_error ? thd->stmt_da->message() : "unexpected success or fatal error"), print_slave_db_safe(thd->db), query_arg); thd->is_slave_error= 1; @@ -4525,13 +4526,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_id = next_query_id(); VOID(pthread_mutex_unlock(&LOCK_thread_count)); - /* - Initing thd->row_count is not necessary in theory as this variable has no - influence in the case of the slave SQL thread (it is used to generate a - "data truncated" warning but which is absorbed and never gets to the - error log); still we init it to avoid a Valgrind message. - */ - mysql_reset_errors(thd, 0); + thd->warning_info->opt_clear_warning_info(thd->query_id); TABLE_LIST tables; bzero((char*) &tables,sizeof(tables)); @@ -4692,8 +4687,8 @@ error: int sql_errno; if (thd->is_error()) { - err= thd->main_da.message(); - sql_errno= thd->main_da.sql_errno(); + err= thd->stmt_da->message(); + sql_errno= thd->stmt_da->sql_errno(); } else { @@ -7256,7 +7251,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) { - uint actual_error= thd->main_da.sql_errno(); + uint actual_error= thd->stmt_da->sql_errno(); if (thd->is_slave_error || thd->is_fatal_error) { /* @@ -7267,7 +7262,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) */ rli->report(ERROR_LEVEL, actual_error, "Error '%s' on opening tables", - (actual_error ? thd->main_da.message() : + (actual_error ? thd->stmt_da->message() : "unexpected success or fatal error")); thd->is_slave_error= 1; } diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 68cd2bf4673..49181bcf543 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -78,7 +78,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) { - uint actual_error= thd->main_da.sql_errno(); + uint actual_error= thd->stmt_da->sql_errno(); if (thd->is_slave_error || thd->is_fatal_error) { /* @@ -87,7 +87,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info */ rli->report(ERROR_LEVEL, actual_error, "Error '%s' on opening tables", - (actual_error ? thd->main_da.message() : + (actual_error ? thd->stmt_da->message() : "unexpected success or fatal error")); thd->is_slave_error= 1; } @@ -216,10 +216,10 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info break; default: - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), + rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(), "Error in %s event: row application failed. %s", ev->get_type_str(), - thd->is_error() ? thd->main_da.message() : ""); + thd->is_error() ? thd->stmt_da->message() : ""); thd->is_slave_error= 1; break; } @@ -245,12 +245,12 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info if (error) { /* error has occured during the transaction */ - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), + rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(), "Error in %s event: error during transaction execution " "on table %s.%s. %s", ev->get_type_str(), table->s->db.str, table->s->table_name.str, - thd->is_error() ? thd->main_da.message() : ""); + thd->is_error() ? thd->stmt_da->message() : ""); /* If one day we honour --skip-slave-errors in row-based replication, and diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 208ddefb890..16d07526a0f 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -41,17 +41,17 @@ int decimal_operation_results(int result) "", (long)-1); break; case E_DEC_OVERFLOW: - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRUNCATED_WRONG_VALUE, ER(ER_TRUNCATED_WRONG_VALUE), "DECIMAL", ""); break; case E_DEC_DIV_ZERO: - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO)); break; case E_DEC_BAD_NUM: - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), "decimal", "", "", (long)-1); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index cd1a31f0fab..71f4619d6b8 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -128,6 +128,10 @@ extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ; extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *national_charset_info; extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *table_alias_charset; +/** + Character set of the buildin error messages loaded from errmsg.sys. +*/ +extern CHARSET_INFO *error_message_charset_info; enum Derivation { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5dad29a1ab7..6d0a5adc1ad 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -628,6 +628,7 @@ MY_BITMAP temp_pool; CHARSET_INFO *system_charset_info, *files_charset_info ; CHARSET_INFO *national_charset_info, *table_alias_charset; CHARSET_INFO *character_set_filesystem; +CHARSET_INFO *error_message_charset_info; MY_LOCALE *my_default_lc_time_names; @@ -1808,7 +1809,8 @@ void close_connection(THD *thd, uint errcode, bool lock) if ((vio= thd->net.vio) != 0) { if (errcode) - net_send_error(thd, errcode, ER(errcode)); /* purecov: inspected */ + net_send_error(thd, errcode, + ER(errcode), NULL); /* purecov: inspected */ vio_close(vio); /* vio is freed in delete thd */ } if (lock) @@ -2854,11 +2856,11 @@ static void check_data_home(const char *path) for the client. */ /* ARGSUSED */ -extern "C" int my_message_sql(uint error, const char *str, myf MyFlags); +extern "C" void my_message_sql(uint error, const char *str, myf MyFlags); -int my_message_sql(uint error, const char *str, myf MyFlags) +void my_message_sql(uint error, const char *str, myf MyFlags) { - THD *thd; + THD *thd= current_thd; DBUG_ENTER("my_message_sql"); DBUG_PRINT("error", ("error: %u message: '%s'", error, str)); @@ -2880,70 +2882,18 @@ int my_message_sql(uint error, const char *str, myf MyFlags) error= ER_UNKNOWN_ERROR; } - if ((thd= current_thd)) + if (thd) { - /* - TODO: There are two exceptions mechanism (THD and sp_rcontext), - this could be improved by having a common stack of handlers. - */ - if (thd->handle_error(error, str, - MYSQL_ERROR::WARN_LEVEL_ERROR)) - DBUG_RETURN(0); - - thd->is_slave_error= 1; // needed to catch query errors during replication - - /* - thd->lex->current_select == 0 if lex structure is not inited - (not query command (COM_QUERY)) - */ - if (thd->lex->current_select && - thd->lex->current_select->no_error && !thd->is_fatal_error) - { - DBUG_PRINT("error", - ("Error converted to warning: current_select: no_error %d " - "fatal_error: %d", - (thd->lex->current_select ? - thd->lex->current_select->no_error : 0), - (int) thd->is_fatal_error)); - } - else - { - if (! thd->main_da.is_error()) // Return only first message - { - thd->main_da.set_error_status(thd, error, str); - } - query_cache_abort(&thd->net); - } - /* - If a continue handler is found, the error message will be cleared - by the stored procedures code. - */ - if (thd->spcont && - ! (MyFlags & ME_NO_SP_HANDLER) && - thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd)) - { - /* - Do not push any warnings, a handled error must be completely - silenced. - */ - DBUG_RETURN(0); - } - - if (!thd->no_warnings_for_error && - !(MyFlags & ME_NO_WARNING_FOR_ERROR)) - { - /* - Suppress infinite recursion if there a memory allocation error - inside push_warning. - */ - thd->no_warnings_for_error= TRUE; - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str); - thd->no_warnings_for_error= FALSE; - } + if (MyFlags & ME_FATALERROR) + thd->is_fatal_error= 1; + (void) thd->raise_condition(error, + NULL, + MYSQL_ERROR::WARN_LEVEL_ERROR, + str); } if (!thd || MyFlags & ME_NOREFRESH) sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */ - DBUG_RETURN(0); + DBUG_VOID_RETURN; } @@ -3107,6 +3057,7 @@ SHOW_VAR com_status_vars[]= { {"replace", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE]), SHOW_LONG_STATUS}, {"replace_select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE_SELECT]), SHOW_LONG_STATUS}, {"reset", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESET]), SHOW_LONG_STATUS}, + {"resignal", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESIGNAL]), SHOW_LONG_STATUS}, {"restore_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESTORE_TABLE]), SHOW_LONG_STATUS}, {"revoke", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE]), SHOW_LONG_STATUS}, {"revoke_all", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE_ALL]), SHOW_LONG_STATUS}, @@ -3115,6 +3066,7 @@ SHOW_VAR com_status_vars[]= { {"savepoint", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SAVEPOINT]), SHOW_LONG_STATUS}, {"select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SELECT]), SHOW_LONG_STATUS}, {"set_option", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SET_OPTION]), SHOW_LONG_STATUS}, + {"signal", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SIGNAL]), SHOW_LONG_STATUS}, {"show_authors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_AUTHORS]), SHOW_LONG_STATUS}, {"show_binlog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOG_EVENTS]), SHOW_LONG_STATUS}, {"show_binlogs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOGS]), SHOW_LONG_STATUS}, @@ -4939,7 +4891,7 @@ void create_thread_to_handle_connection(THD *thd) /* Can't use my_error() since store_globals has not been called. */ my_snprintf(error_message_buff, sizeof(error_message_buff), ER(ER_CANT_CREATE_THREAD), error); - net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff); + net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff, NULL); (void) pthread_mutex_lock(&LOCK_thread_count); close_connection(thd,0,0); delete thd; diff --git a/sql/protocol.cc b/sql/protocol.cc index 4f69a0fdb52..54e17ff5c3b 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -28,13 +28,13 @@ #include static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; +bool net_send_error_packet(THD *, uint, const char *, const char *); /* Declared non-static only because of the embedded library. */ -bool net_send_error_packet(THD *thd, uint sql_errno, const char *err); -bool net_send_ok(THD *, uint, uint, ha_rows, ulonglong, const char *); -bool net_send_eof(THD *thd, uint server_status, uint total_warn_count); +bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *); +/* Declared non-static only because of the embedded library. */ +bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count); #ifndef EMBEDDED_LIBRARY -static bool write_eof_packet(THD *thd, NET *net, - uint server_status, uint total_warn_count); +static bool write_eof_packet(THD *, NET *, uint, uint); #endif #ifndef EMBEDDED_LIBRARY @@ -80,29 +80,33 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) @retval TRUE An error occurred and the message wasn't sent properly */ -bool net_send_error(THD *thd, uint sql_errno, const char *err) +bool net_send_error(THD *thd, uint sql_errno, const char *err, + const char* sqlstate) { DBUG_ENTER("net_send_error"); DBUG_ASSERT(!thd->spcont); DBUG_ASSERT(sql_errno); - DBUG_ASSERT(err && err[0]); + DBUG_ASSERT(err); DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, err)); bool error; + if (sqlstate == NULL) + sqlstate= mysql_errno_to_sqlstate(sql_errno); + /* It's one case when we can push an error even though there is an OK or EOF already. */ - thd->main_da.can_overwrite_status= TRUE; + thd->stmt_da->can_overwrite_status= TRUE; /* Abort multi-result sets */ thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; - error= net_send_error_packet(thd, sql_errno, err); + error= net_send_error_packet(thd, sql_errno, err, sqlstate); - thd->main_da.can_overwrite_status= FALSE; + thd->stmt_da->can_overwrite_status= FALSE; DBUG_RETURN(error); } @@ -124,7 +128,7 @@ bool net_send_error(THD *thd, uint sql_errno, const char *err) @param thd Thread handler @param server_status The server status - @param total_warn_count Total number of warnings + @param statement_warn_count Total number of warnings @param affected_rows Number of rows changed by statement @param id Auto_increment id for first row (if used) @param message Message to send to the client (Used by mysql_status) @@ -138,8 +142,8 @@ bool net_send_error(THD *thd, uint sql_errno, const char *err) #ifndef EMBEDDED_LIBRARY bool net_send_ok(THD *thd, - uint server_status, uint total_warn_count, - ha_rows affected_rows, ulonglong id, const char *message) + uint server_status, uint statement_warn_count, + ulonglong affected_rows, ulonglong id, const char *message) { NET *net= &thd->net; uchar buff[MYSQL_ERRMSG_SIZE+10],*pos; @@ -162,12 +166,12 @@ net_send_ok(THD *thd, (ulong) affected_rows, (ulong) id, (uint) (server_status & 0xffff), - (uint) total_warn_count)); + (uint) statement_warn_count)); int2store(pos, server_status); pos+=2; /* We can only return up to 65535 warnings in two bytes */ - uint tmp= min(total_warn_count, 65535); + uint tmp= min(statement_warn_count, 65535); int2store(pos, tmp); pos+= 2; } @@ -176,7 +180,7 @@ net_send_ok(THD *thd, int2store(pos, server_status); pos+=2; } - thd->main_da.can_overwrite_status= TRUE; + thd->stmt_da->can_overwrite_status= TRUE; if (message && message[0]) pos= net_store_data(pos, (uchar*) message, strlen(message)); @@ -184,7 +188,7 @@ net_send_ok(THD *thd, if (!error) error= net_flush(net); - thd->main_da.can_overwrite_status= FALSE; + thd->stmt_da->can_overwrite_status= FALSE; DBUG_PRINT("info", ("OK sent, so no more error sending allowed")); DBUG_RETURN(error); @@ -208,7 +212,7 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ @param thd Thread handler @param server_status The server status - @param total_warn_count Total number of warnings + @param statement_warn_count Total number of warnings @return @retval FALSE The message was successfully sent @@ -216,7 +220,7 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ */ bool -net_send_eof(THD *thd, uint server_status, uint total_warn_count) +net_send_eof(THD *thd, uint server_status, uint statement_warn_count) { NET *net= &thd->net; bool error= FALSE; @@ -224,11 +228,11 @@ net_send_eof(THD *thd, uint server_status, uint total_warn_count) /* Set to TRUE if no active vio, to work well in case of --init-file */ if (net->vio != 0) { - thd->main_da.can_overwrite_status= TRUE; - error= write_eof_packet(thd, net, server_status, total_warn_count); + thd->stmt_da->can_overwrite_status= TRUE; + error= write_eof_packet(thd, net, server_status, statement_warn_count); if (!error) error= net_flush(net); - thd->main_da.can_overwrite_status= FALSE; + thd->stmt_da->can_overwrite_status= FALSE; DBUG_PRINT("info", ("EOF sent, so no more error sending allowed")); } DBUG_RETURN(error); @@ -242,7 +246,7 @@ net_send_eof(THD *thd, uint server_status, uint total_warn_count) @param thd The thread handler @param net The network handler @param server_status The server status - @param total_warn_count The number of warnings + @param statement_warn_count The number of warnings @return @@ -252,7 +256,7 @@ net_send_eof(THD *thd, uint server_status, uint total_warn_count) static bool write_eof_packet(THD *thd, NET *net, uint server_status, - uint total_warn_count) + uint statement_warn_count) { bool error; if (thd->client_capabilities & CLIENT_PROTOCOL_41) @@ -262,7 +266,7 @@ static bool write_eof_packet(THD *thd, NET *net, Don't send warn count during SP execution, as the warn_list is cleared between substatements, and mysqltest gets confused */ - uint tmp= min(total_warn_count, 65535); + uint tmp= min(statement_warn_count, 65535); buff[0]= 254; int2store(buff+1, tmp); /* @@ -309,7 +313,9 @@ bool send_old_password_request(THD *thd) @retval TRUE An error occurred and the messages wasn't sent properly */ -bool net_send_error_packet(THD *thd, uint sql_errno, const char *err) +bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, + const char* sqlstate) + { NET *net= &thd->net; uint length; @@ -338,7 +344,7 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err) { /* The first # is to make the protocol backward compatible */ buff[2]= '#'; - pos= (uchar*) strmov((char*) buff+3, mysql_errno_to_sqlstate(sql_errno)); + pos= (uchar*) strmov((char*) buff+3, sqlstate); } length= (uint) (strmake((char*) pos, err, MYSQL_ERRMSG_SIZE-1) - (char*) buff); @@ -430,45 +436,45 @@ static uchar *net_store_length_fast(uchar *packet, uint length) void net_end_statement(THD *thd) { - DBUG_ASSERT(! thd->main_da.is_sent); + DBUG_ASSERT(! thd->stmt_da->is_sent); /* Can not be true, but do not take chances in production. */ - if (thd->main_da.is_sent) + if (thd->stmt_da->is_sent) return; bool error= FALSE; - switch (thd->main_da.status()) { + switch (thd->stmt_da->status()) { case Diagnostics_area::DA_ERROR: /* The query failed, send error to log and abort bootstrap. */ error= net_send_error(thd, - thd->main_da.sql_errno(), - thd->main_da.message()); + thd->stmt_da->sql_errno(), + thd->stmt_da->message(), + thd->stmt_da->get_sqlstate()); break; case Diagnostics_area::DA_EOF: error= net_send_eof(thd, - thd->main_da.server_status(), - thd->main_da.total_warn_count()); + thd->stmt_da->server_status(), + thd->stmt_da->statement_warn_count()); break; case Diagnostics_area::DA_OK: error= net_send_ok(thd, - thd->main_da.server_status(), - thd->main_da.total_warn_count(), - thd->main_da.affected_rows(), - thd->main_da.last_insert_id(), - thd->main_da.message()); + thd->stmt_da->server_status(), + thd->stmt_da->statement_warn_count(), + thd->stmt_da->affected_rows(), + thd->stmt_da->last_insert_id(), + thd->stmt_da->message()); break; case Diagnostics_area::DA_DISABLED: break; case Diagnostics_area::DA_EMPTY: default: DBUG_ASSERT(0); - error= net_send_ok(thd, thd->server_status, thd->total_warn_count, - 0, 0, NULL); + error= net_send_ok(thd, thd->server_status, 0, 0, 0, NULL); break; } if (!error) - thd->main_da.is_sent= TRUE; + thd->stmt_da->is_sent= TRUE; } @@ -711,7 +717,8 @@ bool Protocol::send_fields(List *list, uint flags) to show that there is no cursor. Send no warning information, as it will be sent at statement end. */ - write_eof_packet(thd, &thd->net, thd->server_status, thd->total_warn_count); + write_eof_packet(thd, &thd->net, thd->server_status, + thd->warning_info->statement_warn_count()); } DBUG_RETURN(prepare_for_send(list)); diff --git a/sql/protocol.h b/sql/protocol.h index 251ba6fbc33..1e584295028 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -17,6 +17,7 @@ #pragma interface /* gcc class implementation */ #endif +#include "sql_error.h" class i_string; class THD; @@ -173,7 +174,8 @@ public: }; void send_warning(THD *thd, uint sql_errno, const char *err=0); -bool net_send_error(THD *thd, uint sql_errno=0, const char *err=0); +bool net_send_error(THD *thd, uint sql_errno, const char *err, + const char* sqlstate); void net_end_statement(THD *thd); bool send_old_password_request(THD *thd); uchar *net_store_data(uchar *to,const uchar *from, size_t length); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 582348608de..e470317abef 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -913,7 +913,7 @@ bool load_master_data(THD* thd) goto err; } /* Clear the result of mysql_create_db(). */ - thd->main_da.reset_diagnostics_area(); + thd->stmt_da->reset_diagnostics_area(); if (mysql_select_db(&mysql, db) || mysql_real_query(&mysql, STRING_WITH_LEN("SHOW TABLES")) || diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 18fbae9bb9d..61d3840569f 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -183,7 +183,7 @@ int init_relay_log_info(Relay_log_info* rli, { sql_print_error("Failed to create a new relay log info file (\ file '%s', errno %d)", fname, my_errno); - msg= current_thd->main_da.message(); + msg= current_thd->stmt_da->message(); goto err; } if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0, @@ -191,7 +191,7 @@ file '%s', errno %d)", fname, my_errno); { sql_print_error("Failed to create a cache on relay log info file '%s'", fname); - msg= current_thd->main_da.message(); + msg= current_thd->stmt_da->message(); goto err; } diff --git a/sql/set_var.cc b/sql/set_var.cc index 0b89333ce03..185fc33deb9 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3132,17 +3132,13 @@ static int check_pseudo_thread_id(THD *thd, set_var *var) static uchar *get_warning_count(THD *thd) { - thd->sys_var_tmp.long_value= - (thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] + - thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] + - thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]); + thd->sys_var_tmp.long_value= thd->warning_info->warn_count(); return (uchar*) &thd->sys_var_tmp.long_value; } static uchar *get_error_count(THD *thd) { - thd->sys_var_tmp.long_value= - thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR]; + thd->sys_var_tmp.long_value= thd->warning_info->error_count(); return (uchar*) &thd->sys_var_tmp.long_value; } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5531ee71620..4c5a4bf120f 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -4879,13 +4879,7 @@ ER_ZLIB_Z_DATA_ERROR por "ZLIB: Dados de entrada está corrupto" spa "ZLIB: Dato de entrada fué corrompido para zlib" ER_CUT_VALUE_GROUP_CONCAT - eng "%d line(s) were cut by GROUP_CONCAT()" - ger "%d Zeile(n) durch GROUP_CONCAT() abgeschnitten" - nla "%d regel(s) door GROUP_CONCAT() ingekort" - por "%d linha(s) foram cortada(s) por GROUP_CONCAT()" - spa "%d línea(s) fue(fueron) cortadas por group_concat()" - swe "%d rad(er) kapades av group_concat()" - ukr "%d line(s) was(were) cut by group_concat()" + eng "Row %u was cut by GROUP_CONCAT()" ER_WARN_TOO_FEW_RECORDS 01000 eng "Row %ld doesn't contain data for all columns" ger "Zeile %ld enthält nicht für alle Felder Daten" @@ -6206,3 +6200,31 @@ ER_TOO_MANY_CONCURRENT_TRXS WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED eng "Non-ASCII separator arguments are not fully supported" + +ER_DUP_SIGNAL_SET 42000 + eng "Duplicate condition information item '%s'" + +# Note that the SQLSTATE is not 01000, it is provided by SIGNAL/RESIGNAL +ER_SIGNAL_WARN 01000 + eng "Unhandled user-defined warning condition" + +# Note that the SQLSTATE is not 02000, it is provided by SIGNAL/RESIGNAL +ER_SIGNAL_NOT_FOUND 02000 + eng "Unhandled user-defined not found condition" + +# Note that the SQLSTATE is not HY000, it is provided by SIGNAL/RESIGNAL +ER_SIGNAL_EXCEPTION HY000 + eng "Unhandled user-defined exception condition" + +ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER 0K000 + eng "RESIGNAL when handler not active" + +ER_SIGNAL_BAD_CONDITION_TYPE + eng "SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE" + +WARN_COND_ITEM_TRUNCATED + eng "Data truncated for condition item '%s'" + +ER_COND_ITEM_TOO_LONG + eng "Data too long for condition item '%s'" + diff --git a/sql/slave.cc b/sql/slave.cc index fac9ee214c5..7ad282c0f24 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1274,7 +1274,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, else { /* Clear the OK result of mysql_rm_table(). */ - thd->main_da.reset_diagnostics_area(); + thd->stmt_da->reset_diagnostics_area(); } } @@ -1297,7 +1297,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, goto err; // mysql_parse took care of the error send thd_proc_info(thd, "Opening master dump table"); - thd->main_da.reset_diagnostics_area(); /* cleanup from CREATE_TABLE */ + thd->stmt_da->reset_diagnostics_area(); /* cleanup from CREATE_TABLE */ /* Note: If this function starts to fail for MERGE tables, change the next two lines to these: @@ -2011,7 +2011,7 @@ static int has_temporary_error(THD *thd) DBUG_ENTER("has_temporary_error"); DBUG_EXECUTE_IF("all_errors_are_temporary_errors", - if (thd->main_da.is_error()) + if (thd->stmt_da->is_error()) { thd->clear_error(); my_error(ER_LOCK_DEADLOCK, MYF(0)); @@ -2030,20 +2030,21 @@ static int has_temporary_error(THD *thd) currently, InnoDB deadlock detected by InnoDB or lock wait timeout (innodb_lock_wait_timeout exceeded */ - if (thd->main_da.sql_errno() == ER_LOCK_DEADLOCK || - thd->main_da.sql_errno() == ER_LOCK_WAIT_TIMEOUT) + if (thd->stmt_da->sql_errno() == ER_LOCK_DEADLOCK || + thd->stmt_da->sql_errno() == ER_LOCK_WAIT_TIMEOUT) DBUG_RETURN(1); #ifdef HAVE_NDB_BINLOG /* currently temporary error set in ndbcluster */ - List_iterator_fast it(thd->warn_list); + List_iterator_fast it(thd->warning_info->warn_list()); MYSQL_ERROR *err; while ((err= it++)) { - DBUG_PRINT("info", ("has warning %d %s", err->code, err->msg)); - switch (err->code) + DBUG_PRINT("info", ("has condition %d %s", err->get_sql_errno(), + err->get_message_text())); + switch (err->get_sql_errno()) { case ER_GET_TEMPORARY_ERRMSG: DBUG_RETURN(1); @@ -2977,9 +2978,9 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, if (check_temp_dir(rli->slave_patternload_file)) { - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), + rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(), "Unable to use slave's temporary directory %s - %s", - slave_load_tmpdir, thd->main_da.message()); + slave_load_tmpdir, thd->stmt_da->message()); goto err; } @@ -2989,7 +2990,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, execute_init_command(thd, &sys_init_slave, &LOCK_sys_init_slave); if (thd->is_slave_error) { - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), + rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(), "Slave SQL thread aborted. Can't execute init_slave query"); goto err; } @@ -3033,20 +3034,20 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, if (thd->is_error()) { - char const *const errmsg= thd->main_da.message(); + char const *const errmsg= thd->stmt_da->message(); DBUG_PRINT("info", - ("thd->main_da.sql_errno()=%d; rli->last_error.number=%d", - thd->main_da.sql_errno(), last_errno)); + ("thd->stmt_da->sql_errno()=%d; rli->last_error.number=%d", + thd->stmt_da->sql_errno(), last_errno)); if (last_errno == 0) { /* This function is reporting an error which was not reported while executing exec_relay_log_event(). */ - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), errmsg); + rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(), errmsg); } - else if (last_errno != thd->main_da.sql_errno()) + else if (last_errno != thd->stmt_da->sql_errno()) { /* * An error was reported while executing exec_relay_log_event() @@ -3055,12 +3056,12 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, * what caused the problem. */ sql_print_error("Slave (additional info): %s Error_code: %d", - errmsg, thd->main_da.sql_errno()); + errmsg, thd->stmt_da->sql_errno()); } } /* Print any warnings issued */ - List_iterator_fast it(thd->warn_list); + List_iterator_fast it(thd->warning_info->warn_list()); MYSQL_ERROR *err; /* Added controlled slave thread cancel for replication @@ -3069,9 +3070,9 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, bool udf_error = false; while ((err= it++)) { - if (err->code == ER_CANT_OPEN_LIBRARY) + if (err->get_sql_errno() == ER_CANT_OPEN_LIBRARY) udf_error = true; - sql_print_warning("Slave: %s Error_code: %d",err->msg, err->code); + sql_print_warning("Slave: %s Error_code: %d", err->get_message_text(), err->get_sql_errno()); } if (udf_error) sql_print_error("Error loading user-defined library, slave SQL " diff --git a/sql/sp.cc b/sql/sp.cc index 4d840f53e2f..5898e553320 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -522,16 +522,24 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) struct Silence_deprecated_warning : public Internal_error_handler { public: - virtual bool handle_error(uint sql_errno, const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd); + 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); }; bool -Silence_deprecated_warning::handle_error(uint sql_errno, const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd) +Silence_deprecated_warning::handle_condition( + THD *, + uint sql_errno, + const char*, + MYSQL_ERROR::enum_warning_level level, + const char*, + MYSQL_ERROR ** cond_hdl) { + *cond_hdl= NULL; if (sql_errno == ER_WARN_DEPRECATED_SYNTAX && level == MYSQL_ERROR::WARN_LEVEL_WARN) return TRUE; @@ -1336,7 +1344,7 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any) &thd->sp_proc_cache, FALSE) != NULL || sp_find_routine(thd, TYPE_ENUM_FUNCTION, name, &thd->sp_func_cache, FALSE) != NULL; - mysql_reset_errors(thd, TRUE); + thd->warning_info->clear_warning_info(thd->query_id); if (sp_object_found) { if (any) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index aed19b76011..908f0997be6 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1083,6 +1083,7 @@ sp_head::execute(THD *thd) Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; Object_creation_ctx *saved_creation_ctx; + Warning_info *saved_warning_info, warning_info(thd->warning_info->warn_id()); /* Use some extra margin for possible SP recursion and functions */ if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (uchar*)&old_packet)) @@ -1131,6 +1132,11 @@ sp_head::execute(THD *thd) thd->is_slave_error= 0; old_arena= thd->stmt_arena; + /* Push a new warning information area. */ + warning_info.append_warning_info(thd, thd->warning_info); + saved_warning_info= thd->warning_info; + thd->warning_info= &warning_info; + /* Switch query context. This has to be done early as this is sometimes allocated trough sql_alloc @@ -1278,29 +1284,33 @@ sp_head::execute(THD *thd) */ if (ctx) { - uint hf; + uint handler_index; - switch (ctx->found_handler(&hip, &hf)) { + switch (ctx->found_handler(& hip, & handler_index)) { case SP_HANDLER_NONE: break; case SP_HANDLER_CONTINUE: thd->restore_active_arena(&execute_arena, &backup_arena); thd->set_n_backup_active_arena(&execute_arena, &backup_arena); ctx->push_hstack(i->get_cont_dest()); - // Fall through + /* Fall through */ default: + if (ctx->end_partial_result_set) + thd->protocol->end_partial_result_set(thd); ip= hip; err_status= FALSE; ctx->clear_handler(); - ctx->enter_handler(hip); + ctx->enter_handler(hip, handler_index); thd->clear_error(); thd->is_fatal_error= 0; thd->killed= THD::NOT_KILLED; thd->mysys_var->abort= 0; continue; } + + ctx->end_partial_result_set= FALSE; } - } while (!err_status && !thd->killed); + } while (!err_status && !thd->killed && !thd->is_fatal_error); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.finish_current_query(); @@ -1334,6 +1344,10 @@ sp_head::execute(THD *thd) thd->stmt_arena= old_arena; state= EXECUTED; + /* Restore the caller's original warning information area. */ + saved_warning_info->merge_with_routine_info(thd, thd->warning_info); + thd->warning_info= saved_warning_info; + done: DBUG_PRINT("info", ("err_status: %d killed: %d is_slave_error: %d report_error: %d", err_status, thd->killed, thd->is_slave_error, @@ -2523,7 +2537,8 @@ void sp_head::optimize() else { if (src != dst) - { // Move the instruction and update prev. jumps + { + /* Move the instruction and update prev. jumps */ sp_instr *ibp; List_iterator_fast li(bp); @@ -2848,7 +2863,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) { res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); - if (thd->main_da.is_eof()) + if (thd->stmt_da->is_eof()) net_end_statement(thd); query_cache_end_of_result(thd); @@ -2862,7 +2877,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) thd->query_name_consts= 0; if (!thd->is_error()) - thd->main_da.reset_diagnostics_area(); + thd->stmt_da->reset_diagnostics_area(); } DBUG_RETURN(res || thd->is_error()); } @@ -3238,7 +3253,7 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp) sp_cond_type_t *p; while ((p= li++)) - thd->spcont->push_handler(p, m_ip+1, m_type, m_frame); + thd->spcont->push_handler(p, m_ip+1, m_type); *nextp= m_dest; DBUG_RETURN(0); diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 302faf3f681..31c307ebe74 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -51,7 +51,8 @@ sp_cond_check(LEX_STRING *sqlstate) (c < 'A' || 'Z' < c)) return FALSE; } - if (strcmp(sqlstate->str, "00000") == 0) + /* SQLSTATE class '00' : completion condition */ + if (strncmp(sqlstate->str, "00", 2) == 0) return FALSE; return TRUE; } diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 3145ba2fea4..75e55880e60 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -71,7 +71,7 @@ typedef struct sp_label typedef struct sp_cond_type { enum { number, state, warning, notfound, exception } type; - char sqlstate[6]; + char sqlstate[SQLSTATE_LENGTH+1]; uint mysqlerr; } sp_cond_type_t; diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 9b237b3e7cc..51b797fe088 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -32,7 +32,8 @@ sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld, sp_rcontext *prev_runtime_ctx) - :m_root_parsing_ctx(root_parsing_ctx), + :end_partial_result_set(FALSE), + m_root_parsing_ctx(root_parsing_ctx), m_var_table(0), m_var_items(0), m_return_value_fld(return_value_fld), @@ -68,21 +69,28 @@ sp_rcontext::~sp_rcontext() bool sp_rcontext::init(THD *thd) { + uint handler_count= m_root_parsing_ctx->max_handler_index(); + uint i; + in_sub_stmt= thd->in_sub_stmt; if (init_var_table(thd) || init_var_items()) return TRUE; + if (!(m_raised_conditions= new (thd->mem_root) MYSQL_ERROR[handler_count])) + return TRUE; + + for (i= 0; imem_root); + return !(m_handler= - (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handler_index() * - sizeof(sp_handler_t))) || + (sp_handler_t*)thd->alloc(handler_count * sizeof(sp_handler_t))) || !(m_hstack= - (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() * - sizeof(uint))) || + (uint*)thd->alloc(handler_count * sizeof(uint))) || !(m_in_handler= - (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() * - sizeof(uint))) || + (sp_active_handler_t*)thd->alloc(handler_count * + sizeof(sp_active_handler_t))) || !(m_cstack= (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursor_index() * sizeof(sp_cursor*))) || @@ -194,13 +202,19 @@ sp_rcontext::set_return_value(THD *thd, Item **return_value_item) */ bool -sp_rcontext::find_handler(THD *thd, uint sql_errno, - MYSQL_ERROR::enum_warning_level level) +sp_rcontext::find_handler(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) { if (m_hfound >= 0) - return 1; // Already got one + { + *cond_hdl= NULL; + return TRUE; // Already got one + } - const char *sqlstate= mysql_errno_to_sqlstate(sql_errno); int i= m_hcount, found= -1; /* @@ -220,7 +234,7 @@ sp_rcontext::find_handler(THD *thd, uint sql_errno, /* Check active handlers, to avoid invoking one recursively */ while (j--) - if (m_in_handler[j] == m_handler[i].handler) + if (m_in_handler[j].ip == m_handler[i].handler) break; if (j >= 0) continue; // Already executing this handler @@ -264,10 +278,26 @@ sp_rcontext::find_handler(THD *thd, uint sql_errno, */ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR) - return m_prev_runtime_ctx->find_handler(thd, sql_errno, level); + return m_prev_runtime_ctx->find_handler(thd, + sql_errno, + sqlstate, + level, + msg, + cond_hdl); + *cond_hdl= NULL; return FALSE; } + m_hfound= found; + + MYSQL_ERROR *raised= NULL; + DBUG_ASSERT(m_hfound >= 0); + DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index()); + raised= & m_raised_conditions[m_hfound]; + raised->clear(); + raised->set(sql_errno, sqlstate, level, msg); + + *cond_hdl= raised; return TRUE; } @@ -293,9 +323,12 @@ sp_rcontext::find_handler(THD *thd, uint sql_errno, FALSE if no handler was found. */ bool -sp_rcontext::handle_error(uint sql_errno, - MYSQL_ERROR::enum_warning_level level, - THD *thd) +sp_rcontext::handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) { MYSQL_ERROR::enum_warning_level elevated_level= level; @@ -308,7 +341,7 @@ sp_rcontext::handle_error(uint sql_errno, elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR; } - return find_handler(thd, sql_errno, elevated_level); + return find_handler(thd, sql_errno, sqlstate, elevated_level, msg, cond_hdl); } void @@ -335,7 +368,7 @@ sp_rcontext::pop_cursors(uint count) } void -sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type, uint f) +sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type) { DBUG_ENTER("sp_rcontext::push_handler"); DBUG_ASSERT(m_hcount < m_root_parsing_ctx->max_handler_index()); @@ -343,7 +376,6 @@ sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type, uint f) m_handler[m_hcount].cond= cond; m_handler[m_hcount].handler= h; m_handler[m_hcount].type= type; - m_handler[m_hcount].foffset= f; m_hcount+= 1; DBUG_PRINT("info", ("m_hcount: %d", m_hcount)); @@ -382,11 +414,13 @@ sp_rcontext::pop_hstack() } void -sp_rcontext::enter_handler(int hid) +sp_rcontext::enter_handler(uint hip, uint hindex) { DBUG_ENTER("sp_rcontext::enter_handler"); DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index()); - m_in_handler[m_ihsp++]= hid; + m_in_handler[m_ihsp].ip= hip; + m_in_handler[m_ihsp].index= hindex; + m_ihsp++; DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp)); DBUG_VOID_RETURN; } @@ -396,11 +430,29 @@ sp_rcontext::exit_handler() { DBUG_ENTER("sp_rcontext::exit_handler"); DBUG_ASSERT(m_ihsp); + uint hindex= m_in_handler[m_ihsp-1].index; + m_raised_conditions[hindex].clear(); m_ihsp-= 1; DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp)); DBUG_VOID_RETURN; } +MYSQL_ERROR* +sp_rcontext::raised_condition() const +{ + if (m_ihsp > 0) + { + uint hindex= m_in_handler[m_ihsp - 1].index; + MYSQL_ERROR *raised= & m_raised_conditions[hindex]; + return raised; + } + + if (m_prev_runtime_ctx) + return m_prev_runtime_ctx->raised_condition(); + + return NULL; +} + int sp_rcontext::set_variable(THD *thd, uint var_idx, Item **value) diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 368a017da21..2af96cf64dd 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -34,12 +34,21 @@ class sp_instr_cpush; typedef struct { + /** Condition caught by this HANDLER. */ struct sp_cond_type *cond; - uint handler; // Location of handler + /** Location (instruction pointer) of the handler code. */ + uint handler; + /** Handler type (EXIT, CONTINUE). */ int type; - uint foffset; // Frame offset for the handlers declare level } sp_handler_t; +typedef struct +{ + /** Instruction pointer of the active handler. */ + uint ip; + /** Handler index of the active handler. */ + uint index; +} sp_active_handler_t; /* This class is a runtime context of a Stored Routine. It is used in an @@ -75,6 +84,13 @@ class sp_rcontext : public Sql_alloc */ Query_arena *callers_arena; + /* + End a open result set before start executing a continue/exit + handler if one is found as otherwise the client will hang + due to a violation of the client/server protocol. + */ + bool end_partial_result_set; + #ifndef DBUG_OFF /* The routine for which this runtime context is created. Used for checking @@ -107,31 +123,41 @@ class sp_rcontext : public Sql_alloc return m_return_value_set; } - void push_handler(struct sp_cond_type *cond, uint h, int type, uint f); + void push_handler(struct sp_cond_type *cond, uint h, int type); void pop_handlers(uint count); // Returns 1 if a handler was found, 0 otherwise. bool - find_handler(THD *thd, uint sql_errno,MYSQL_ERROR::enum_warning_level level); + find_handler(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl); // If there is an error handler for this error, handle it and return TRUE. bool - handle_error(uint sql_errno, - MYSQL_ERROR::enum_warning_level level, - THD *thd); + handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl); // Returns handler type and sets *ip to location if one was found inline int - found_handler(uint *ip, uint *fp) + found_handler(uint *ip, uint *index) { if (m_hfound < 0) return SP_HANDLER_NONE; *ip= m_handler[m_hfound].handler; - *fp= m_handler[m_hfound].foffset; + *index= m_hfound; return m_handler[m_hfound].type; } + MYSQL_ERROR* raised_condition() const; + // Returns true if we found a handler in this context inline bool found_handler_here() @@ -150,7 +176,12 @@ class sp_rcontext : public Sql_alloc uint pop_hstack(); - void enter_handler(int hid); + /** + Enter a SQL exception handler. + @param hip the handler instruction pointer + @param index the handler index + */ + void enter_handler(uint hip, uint index); void exit_handler(); @@ -214,10 +245,18 @@ private: bool in_sub_stmt; sp_handler_t *m_handler; // Visible handlers + + /** + SQL conditions caught by each handler. + This is an array indexed by handler index. + */ + MYSQL_ERROR *m_raised_conditions; + uint m_hcount; // Stack pointer for m_handler uint *m_hstack; // Return stack for continue handlers uint m_hsp; // Stack pointer for m_hstack - uint *m_in_handler; // Active handler, for recursion check + /** Active handler stack. */ + sp_active_handler_t *m_in_handler; uint m_ihsp; // Stack pointer for m_in_handler int m_hfound; // Set by find_handler; -1 if not found diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ab18a2d1d04..9ab13438926 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -702,7 +702,7 @@ my_bool acl_reload(THD *thd) if (simple_open_n_lock_tables(thd, tables)) { sql_print_error("Fatal error: Can't open and lock privilege tables: %s", - thd->main_da.message()); + thd->stmt_da->message()); goto end; } @@ -6036,9 +6036,12 @@ public: virtual ~Silence_routine_definer_errors() {} - virtual bool handle_error(uint sql_errno, const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd); + 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); bool has_errors() { return is_grave; } @@ -6047,18 +6050,23 @@ private: }; bool -Silence_routine_definer_errors::handle_error(uint sql_errno, - const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd) +Silence_routine_definer_errors::handle_condition( + THD *thd, + uint sql_errno, + const char*, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) { + *cond_hdl= NULL; if (level == MYSQL_ERROR::WARN_LEVEL_ERROR) { switch (sql_errno) { case ER_NONEXISTING_PROC_GRANT: /* Convert the error into a warning. */ - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, message); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + sql_errno, msg); return TRUE; default: is_grave= TRUE; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b81070000b3..92ae390894a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -44,9 +44,12 @@ public: virtual ~Prelock_error_handler() {} - virtual bool handle_error(uint sql_errno, const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd); + 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); bool safely_trapped_errors(); @@ -57,11 +60,14 @@ private: bool -Prelock_error_handler::handle_error(uint sql_errno, - const char * /* message */, - MYSQL_ERROR::enum_warning_level /* level */, - THD * /* thd */) +Prelock_error_handler::handle_condition(THD *, + uint sql_errno, + const char*, + MYSQL_ERROR::enum_warning_level, + const char*, + MYSQL_ERROR ** cond_hdl) { + *cond_hdl= NULL; if (sql_errno == ER_NO_SUCH_TABLE) { m_handled_errors++; @@ -473,7 +479,7 @@ static TABLE_SHARE @todo Rework alternative ways to deal with ER_NO_SUCH TABLE. */ - if (share || (thd->is_error() && thd->main_da.sql_errno() != ER_NO_SUCH_TABLE)) + if (share || (thd->is_error() && thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE)) DBUG_RETURN(share); @@ -520,7 +526,7 @@ static TABLE_SHARE DBUG_RETURN(0); } /* Table existed in engine. Let's open it */ - mysql_reset_errors(thd, 1); // Clear warnings + thd->warning_info->clear_warning_info(thd->query_id); thd->clear_error(); // Clear error message DBUG_RETURN(get_table_share(thd, table_list, key, key_length, db_flags, error)); @@ -1281,9 +1287,9 @@ void close_thread_tables(THD *thd) */ if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL)) { - thd->main_da.can_overwrite_status= TRUE; + thd->stmt_da->can_overwrite_status= TRUE; ha_autocommit_or_rollback(thd, thd->is_error()); - thd->main_da.can_overwrite_status= FALSE; + thd->stmt_da->can_overwrite_status= FALSE; /* Reset transaction state, but only if we're not inside a @@ -3943,7 +3949,7 @@ retry: release_table_share(share, RELEASE_WAIT_FOR_DROP); if (!thd->killed) { - mysql_reset_errors(thd, 1); // Clear warnings + thd->warning_info->clear_warning_info(thd->query_id); thd->clear_error(); // Clear error message goto retry; } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 3c4ee274e7b..9f427f39265 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -934,7 +934,7 @@ void query_cache_end_of_result(THD *thd) DBUG_VOID_RETURN; /* Ensure that only complete results are cached. */ - DBUG_ASSERT(thd->main_da.is_eof()); + DBUG_ASSERT(thd->stmt_da->is_eof()); if (thd->killed) { @@ -1626,7 +1626,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", thd->limit_found_rows = query->found_rows(); thd->status_var.last_query_cost= 0.0; - thd->main_da.disable_status(); + thd->stmt_da->disable_status(); BLOCK_UNLOCK_RD(query_block); MYSQL_QUERY_CACHE_HIT(thd->query, (ulong) thd->limit_found_rows); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 3f568566c89..0ef7aece3d8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -199,19 +199,6 @@ bool foreign_key_prefix(Key *a, Key *b) ** Thread specific functions ****************************************************************************/ -/** Push an error to the error stack and return TRUE for now. */ - -bool -Reprepare_observer::report_error(THD *thd) -{ - my_error(ER_NEED_REPREPARE, MYF(ME_NO_WARNING_FOR_ERROR|ME_NO_SP_HANDLER)); - - m_invalidated= TRUE; - - return TRUE; -} - - Open_tables_state::Open_tables_state(ulong version_arg) :version(version_arg), state_flags(0U) { @@ -304,7 +291,7 @@ int thd_tx_isolation(const THD *thd) extern "C" void thd_inc_row_count(THD *thd) { - thd->row_count++; + thd->warning_info->inc_current_row_for_warning(); } @@ -399,139 +386,6 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, return buffer; } -/** - Clear this diagnostics area. - - Normally called at the end of a statement. -*/ - -void -Diagnostics_area::reset_diagnostics_area() -{ -#ifdef DBUG_OFF - can_overwrite_status= FALSE; - /** Don't take chances in production */ - m_message[0]= '\0'; - m_sql_errno= 0; - m_server_status= 0; - m_affected_rows= 0; - m_last_insert_id= 0; - m_total_warn_count= 0; -#endif - is_sent= FALSE; - /** Tiny reset in debug mode to see garbage right away */ - m_status= DA_EMPTY; -} - - -/** - Set OK status -- ends commands that do not return a - result set, e.g. INSERT/UPDATE/DELETE. -*/ - -void -Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg, - ulonglong last_insert_id_arg, - const char *message_arg) -{ - DBUG_ASSERT(! is_set()); -#ifdef DBUG_OFF - /* - In production, refuse to overwrite an error or a custom response - with an OK packet. - */ - if (is_error() || is_disabled()) - return; -#endif - /** Only allowed to report success if has not yet reported an error */ - - m_server_status= thd->server_status; - m_total_warn_count= thd->total_warn_count; - m_affected_rows= affected_rows_arg; - m_last_insert_id= last_insert_id_arg; - if (message_arg) - strmake(m_message, message_arg, sizeof(m_message) - 1); - else - m_message[0]= '\0'; - m_status= DA_OK; -} - - -/** - Set EOF status. -*/ - -void -Diagnostics_area::set_eof_status(THD *thd) -{ - /** Only allowed to report eof if has not yet reported an error */ - - DBUG_ASSERT(! is_set()); -#ifdef DBUG_OFF - /* - In production, refuse to overwrite an error or a custom response - with an EOF packet. - */ - if (is_error() || is_disabled()) - return; -#endif - - m_server_status= thd->server_status; - /* - If inside a stored procedure, do not return the total - number of warnings, since they are not available to the client - anyway. - */ - m_total_warn_count= thd->spcont ? 0 : thd->total_warn_count; - - m_status= DA_EOF; -} - -/** - Set ERROR status. -*/ - -void -Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg, - const char *message_arg) -{ - /* - Only allowed to report error if has not yet reported a success - The only exception is when we flush the message to the client, - an error can happen during the flush. - */ - DBUG_ASSERT(! is_set() || can_overwrite_status); -#ifdef DBUG_OFF - /* - In production, refuse to overwrite a custom response with an - ERROR packet. - */ - if (is_disabled()) - return; -#endif - - m_sql_errno= sql_errno_arg; - strmake(m_message, message_arg, sizeof(m_message) - 1); - - m_status= DA_ERROR; -} - - -/** - Mark the diagnostics area as 'DISABLED'. - - This is used in rare cases when the COM_ command at hand sends a response - in a custom format. One example is the query cache, another is - COM_STMT_PREPARE. -*/ - -void -Diagnostics_area::disable_status() -{ - DBUG_ASSERT(! is_set()); - m_status= DA_DISABLED; -} - THD::THD() :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION, @@ -548,6 +402,8 @@ THD::THD() first_successful_insert_id_in_cur_stmt(0), stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE), examined_row_count(0), + warning_info(&main_warning_info), + stmt_da(&main_da), global_read_lock(0), is_fatal_error(0), transaction_rollback_request(0), @@ -558,7 +414,8 @@ THD::THD() bootstrap(0), derived_tables_processing(FALSE), spcont(NULL), - m_parser_state(NULL) + m_parser_state(NULL), + main_warning_info(0) { ulong tmp; @@ -582,7 +439,8 @@ THD::THD() hash_clear(&handler_tables_hash); tmp_table=0; used_tables=0; - cuted_fields= sent_row_count= row_count= 0L; + cuted_fields= 0L; + sent_row_count= 0L; limit_found_rows= 0; row_count_func= -1; statement_id_counter= 0UL; @@ -602,7 +460,6 @@ THD::THD() file_id = 0; query_id= 0; query_name_consts= 0; - warn_id= 0; db_charset= global_system_variables.collation_database; bzero(ha_data, sizeof(ha_data)); mysys_var=0; @@ -638,8 +495,6 @@ THD::THD() *scramble= '\0'; init(); - /* Initialize sub structures */ - init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) profiling.set_thd(this); #endif @@ -687,19 +542,27 @@ void THD::push_internal_handler(Internal_error_handler *handler) } } - -bool THD::handle_error(uint sql_errno, const char *message, - MYSQL_ERROR::enum_warning_level level) +bool THD::handle_condition(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) { if (!m_internal_handler) + { + *cond_hdl= NULL; return FALSE; + } for (Internal_error_handler *error_handler= m_internal_handler; error_handler; error_handler= m_internal_handler->m_prev_internal_handler) { - if (error_handler->handle_error(sql_errno, message, level, this)) - return TRUE; + if (error_handler-> handle_condition(this, sql_errno, sqlstate, level, msg, + cond_hdl)) + { + return TRUE; + } } return FALSE; @@ -712,6 +575,207 @@ void THD::pop_internal_handler() m_internal_handler= m_internal_handler->m_prev_internal_handler; } + +void THD::raise_error(uint sql_errno) +{ + const char* msg= ER(sql_errno); + (void) raise_condition(sql_errno, + NULL, + MYSQL_ERROR::WARN_LEVEL_ERROR, + msg); +} + +void THD::raise_error_printf(uint sql_errno, ...) +{ + va_list args; + char ebuff[MYSQL_ERRMSG_SIZE]; + DBUG_ENTER("THD::raise_error_printf"); + DBUG_PRINT("my", ("nr: %d errno: %d", sql_errno, errno)); + const char* format= ER(sql_errno); + va_start(args, sql_errno); + my_vsnprintf(ebuff, sizeof(ebuff), format, args); + va_end(args); + (void) raise_condition(sql_errno, + NULL, + MYSQL_ERROR::WARN_LEVEL_ERROR, + ebuff); + DBUG_VOID_RETURN; +} + +void THD::raise_warning(uint sql_errno) +{ + const char* msg= ER(sql_errno); + (void) raise_condition(sql_errno, + NULL, + MYSQL_ERROR::WARN_LEVEL_WARN, + msg); +} + +void THD::raise_warning_printf(uint sql_errno, ...) +{ + va_list args; + char ebuff[MYSQL_ERRMSG_SIZE]; + DBUG_ENTER("THD::raise_warning_printf"); + DBUG_PRINT("enter", ("warning: %u", sql_errno)); + const char* format= ER(sql_errno); + va_start(args, sql_errno); + my_vsnprintf(ebuff, sizeof(ebuff), format, args); + va_end(args); + (void) raise_condition(sql_errno, + NULL, + MYSQL_ERROR::WARN_LEVEL_WARN, + ebuff); + DBUG_VOID_RETURN; +} + +void THD::raise_note(uint sql_errno) +{ + DBUG_ENTER("THD::raise_note"); + DBUG_PRINT("enter", ("code: %d", sql_errno)); + if (!(this->options & OPTION_SQL_NOTES)) + DBUG_VOID_RETURN; + const char* msg= ER(sql_errno); + (void) raise_condition(sql_errno, + NULL, + MYSQL_ERROR::WARN_LEVEL_NOTE, + msg); + DBUG_VOID_RETURN; +} + +void THD::raise_note_printf(uint sql_errno, ...) +{ + va_list args; + char ebuff[MYSQL_ERRMSG_SIZE]; + DBUG_ENTER("THD::raise_note_printf"); + DBUG_PRINT("enter",("code: %u", sql_errno)); + if (!(this->options & OPTION_SQL_NOTES)) + DBUG_VOID_RETURN; + const char* format= ER(sql_errno); + va_start(args, sql_errno); + my_vsnprintf(ebuff, sizeof(ebuff), format, args); + va_end(args); + (void) raise_condition(sql_errno, + NULL, + MYSQL_ERROR::WARN_LEVEL_NOTE, + ebuff); + DBUG_VOID_RETURN; +} + +MYSQL_ERROR* THD::raise_condition(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg) +{ + MYSQL_ERROR *cond= NULL; + DBUG_ENTER("THD::raise_condition"); + + if (!(this->options & OPTION_SQL_NOTES) && + (level == MYSQL_ERROR::WARN_LEVEL_NOTE)) + DBUG_RETURN(NULL); + + warning_info->opt_clear_warning_info(query_id); + + /* + TODO: replace by DBUG_ASSERT(sql_errno != 0) once all bugs similar to + Bug#36768 are fixed: a SQL condition must have a real (!=0) error number + so that it can be caught by handlers. + */ + if (sql_errno == 0) + sql_errno= ER_UNKNOWN_ERROR; + if (msg == NULL) + msg= ER(sql_errno); + if (sqlstate == NULL) + sqlstate= mysql_errno_to_sqlstate(sql_errno); + + if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) && + really_abort_on_warning()) + { + /* + FIXME: + push_warning and strict SQL_MODE case. + */ + level= MYSQL_ERROR::WARN_LEVEL_ERROR; + killed= THD::KILL_BAD_DATA; + } + + switch (level) + { + case MYSQL_ERROR::WARN_LEVEL_NOTE: + case MYSQL_ERROR::WARN_LEVEL_WARN: + got_warning= 1; + break; + case MYSQL_ERROR::WARN_LEVEL_ERROR: + break; + default: + DBUG_ASSERT(FALSE); + } + + if (handle_condition(sql_errno, sqlstate, level, msg, &cond)) + DBUG_RETURN(cond); + + if (level == MYSQL_ERROR::WARN_LEVEL_ERROR) + { + is_slave_error= 1; // needed to catch query errors during replication + + /* + thd->lex->current_select == 0 if lex structure is not inited + (not query command (COM_QUERY)) + */ + if (lex->current_select && + lex->current_select->no_error && !is_fatal_error) + { + DBUG_PRINT("error", + ("Error converted to warning: current_select: no_error %d " + "fatal_error: %d", + (lex->current_select ? + lex->current_select->no_error : 0), + (int) is_fatal_error)); + } + else + { + if (! stmt_da->is_error()) + stmt_da->set_error_status(this, sql_errno, msg, sqlstate); + } + } + + /* + If a continue handler is found, the error message will be cleared + by the stored procedures code. + */ + if (!is_fatal_error && spcont && + spcont->handle_condition(this, sql_errno, sqlstate, level, msg, &cond)) + { + /* + Do not push any warnings, a handled error must be completely + silenced. + */ + DBUG_RETURN(cond); + } + + /* Un-handled conditions */ + + cond= raise_condition_no_handler(sql_errno, sqlstate, level, msg); + DBUG_RETURN(cond); +} + +MYSQL_ERROR* +THD::raise_condition_no_handler(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg) +{ + MYSQL_ERROR *cond= NULL; + DBUG_ENTER("THD::raise_condition_no_handler"); + + query_cache_abort(& net); + + /* FIXME: broken special case */ + if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR)) + DBUG_RETURN(NULL); + + cond= warning_info->push_warning(this, sql_errno, sqlstate, level, msg); + DBUG_RETURN(cond); +} extern "C" void *thd_alloc(MYSQL_THD thd, unsigned int size) { @@ -800,9 +864,6 @@ void THD::init(void) TL_WRITE_LOW_PRIORITY : TL_WRITE); session_tx_isolation= (enum_tx_isolation) variables.tx_isolation; - warn_list.empty(); - bzero((char*) warn_count, sizeof(warn_count)); - total_warn_count= 0; update_charset(); reset_current_stmt_binlog_row_based(); bzero((char *) &status_var, sizeof(status_var)); @@ -940,7 +1001,6 @@ THD::~THD() DBUG_PRINT("info", ("freeing security context")); main_security_ctx.destroy(); safeFree(db); - free_root(&warn_root,MYF(0)); #ifdef USING_TRANSACTIONS free_root(&transaction.mem_root,MYF(0)); #endif @@ -1543,21 +1603,19 @@ bool select_send::send_fields(List &list, uint flags) void select_send::abort() { DBUG_ENTER("select_send::abort"); - if (is_result_set_started && thd->spcont && - thd->spcont->find_handler(thd, thd->main_da.sql_errno(), - MYSQL_ERROR::WARN_LEVEL_ERROR)) + + if (is_result_set_started && thd->spcont) { /* We're executing a stored procedure, have an open result - set, an SQL exception condition and a handler for it. - In this situation we must abort the current statement, - silence the error and start executing the continue/exit - handler. + set and an SQL exception condition. In this situation we + must abort the current statement, silence the error and + start executing the continue/exit handler if one is found. Before aborting the statement, let's end the open result set, as otherwise the client will hang due to the violation of the client/server protocol. */ - thd->protocol->end_partial_result_set(thd); + thd->spcont->end_partial_result_set= TRUE; } DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index a8fe3227aeb..d7814fcb03f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -265,6 +265,41 @@ public: LEX_COLUMN (const String& x,const uint& y ): column (x),rights (y) {} }; +/* SIGNAL / RESIGNAL / GET DIAGNOSTICS */ + +/** + This enumeration list all the condition item names of a condition in the + SQL condition area. +*/ +typedef enum enum_diag_condition_item_name +{ + /* + Conditions that can be set by the user (SIGNAL/RESIGNAL), + and by the server implementation. + */ + + DIAG_CLASS_ORIGIN= 0, + FIRST_DIAG_SET_PROPERTY= DIAG_CLASS_ORIGIN, + DIAG_SUBCLASS_ORIGIN= 1, + DIAG_CONSTRAINT_CATALOG= 2, + DIAG_CONSTRAINT_SCHEMA= 3, + DIAG_CONSTRAINT_NAME= 4, + DIAG_CATALOG_NAME= 5, + DIAG_SCHEMA_NAME= 6, + DIAG_TABLE_NAME= 7, + DIAG_COLUMN_NAME= 8, + DIAG_CURSOR_NAME= 9, + DIAG_MESSAGE_TEXT= 10, + DIAG_MYSQL_ERRNO= 11, + LAST_DIAG_SET_PROPERTY= DIAG_MYSQL_ERRNO +} Diag_condition_item_name; + +/** + Name of each diagnostic condition item. + This array is indexed by Diag_condition_item_name. +*/ +extern const LEX_STRING Diag_condition_item_names[]; + #include "sql_lex.h" /* Must be here */ class Delayed_insert; @@ -1038,12 +1073,12 @@ protected: public: /** - Handle an error condition. + Handle a sql condition. This method can be implemented by a subclass to achieve any of the following: - - mask an error internally, prevent exposing it to the user, - - mask an error and throw another one instead. - When this method returns true, the error condition is considered + - mask a warning/error internally, prevent exposing it to the user, + - mask a warning/error and throw another one instead. + When this method returns true, the sql condition is considered 'handled', and will not be propagated to upper layers. It is the responsability of the code installing an internal handler to then check for trapped conditions, and implement logic to recover @@ -1057,15 +1092,17 @@ public: before removing it from the exception stack with THD::pop_internal_handler(). - @param sql_errno the error number - @param level the error level @param thd the calling thread - @return true if the error is handled + @param cond the condition raised. + @return true if the condition is handled */ - virtual bool handle_error(uint sql_errno, - const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd) = 0; + 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) = 0; + private: Internal_error_handler *m_prev_internal_handler; friend class THD; @@ -1080,10 +1117,12 @@ private: class Dummy_error_handler : public Internal_error_handler { public: - bool handle_error(uint sql_errno, - const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd) + bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) { /* Ignore error */ return TRUE; @@ -1091,123 +1130,6 @@ public: }; -/** - Stores status of the currently executed statement. - Cleared at the beginning of the statement, and then - can hold either OK, ERROR, or EOF status. - Can not be assigned twice per statement. -*/ - -class Diagnostics_area -{ -public: - enum enum_diagnostics_status - { - /** The area is cleared at start of a statement. */ - DA_EMPTY= 0, - /** Set whenever one calls my_ok(). */ - DA_OK, - /** Set whenever one calls my_eof(). */ - DA_EOF, - /** Set whenever one calls my_error() or my_message(). */ - DA_ERROR, - /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */ - DA_DISABLED - }; - /** True if status information is sent to the client. */ - bool is_sent; - /** Set to make set_error_status after set_{ok,eof}_status possible. */ - bool can_overwrite_status; - - void set_ok_status(THD *thd, ha_rows affected_rows_arg, - ulonglong last_insert_id_arg, - const char *message); - void set_eof_status(THD *thd); - void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg); - - void disable_status(); - - void reset_diagnostics_area(); - - bool is_set() const { return m_status != DA_EMPTY; } - bool is_error() const { return m_status == DA_ERROR; } - bool is_eof() const { return m_status == DA_EOF; } - bool is_ok() const { return m_status == DA_OK; } - bool is_disabled() const { return m_status == DA_DISABLED; } - enum_diagnostics_status status() const { return m_status; } - - const char *message() const - { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; } - - uint sql_errno() const - { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; } - - uint server_status() const - { - DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF); - return m_server_status; - } - - ha_rows affected_rows() const - { DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; } - - ulonglong last_insert_id() const - { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; } - - uint total_warn_count() const - { - DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF); - return m_total_warn_count; - } - - Diagnostics_area() { reset_diagnostics_area(); } - -private: - /** Message buffer. Can be used by OK or ERROR status. */ - char m_message[MYSQL_ERRMSG_SIZE]; - /** - SQL error number. One of ER_ codes from share/errmsg.txt. - Set by set_error_status. - */ - uint m_sql_errno; - - /** - Copied from thd->server_status when the diagnostics area is assigned. - We need this member as some places in the code use the following pattern: - thd->server_status|= ... - my_eof(thd); - thd->server_status&= ~... - Assigned by OK, EOF or ERROR. - */ - uint m_server_status; - /** - The number of rows affected by the last statement. This is - semantically close to thd->row_count_func, but has a different - life cycle. thd->row_count_func stores the value returned by - function ROW_COUNT() and is cleared only by statements that - update its value, such as INSERT, UPDATE, DELETE and few others. - This member is cleared at the beginning of the next statement. - - We could possibly merge the two, but life cycle of thd->row_count_func - can not be changed. - */ - ha_rows m_affected_rows; - /** - Similarly to the previous member, this is a replacement of - thd->first_successful_insert_id_in_prev_stmt, which is used - to implement LAST_INSERT_ID(). - */ - ulonglong m_last_insert_id; - /** The total number of warnings. */ - uint m_total_warn_count; - enum_diagnostics_status m_status; - /** - @todo: the following THD members belong here: - - warn_list, warn_count, - */ -}; - - /** Storage engine specific thread local data. */ @@ -1234,6 +1156,7 @@ struct Ha_data Ha_data() :ha_ptr(NULL) {} }; +extern "C" void my_message_sql(uint error, const char *str, myf MyFlags); /** @class THD @@ -1276,7 +1199,6 @@ public: struct st_mysql_stmt *current_stmt; #endif NET net; // client connection descriptor - MEM_ROOT warn_root; // For warnings and errors Protocol *protocol; // Current protocol Protocol_text protocol_text; // Normal protocol Protocol_binary protocol_binary; // Binary protocol @@ -1692,16 +1614,8 @@ public: table_map used_tables; USER_CONN *user_connect; CHARSET_INFO *db_charset; - /* - FIXME: this, and some other variables like 'count_cuted_fields' - maybe should be statement/cursor local, that is, moved to Statement - class. With current implementation warnings produced in each prepared - statement/cursor settle here. - */ - List warn_list; - uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; - uint total_warn_count; - Diagnostics_area main_da; + Warning_info *warning_info; + Diagnostics_area *stmt_da; #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) PROFILING profiling; #endif @@ -1714,7 +1628,7 @@ public: from table are necessary for this select, to check if it's necessary to update auto-updatable fields (like auto_increment and timestamp). */ - query_id_t query_id, warn_id; + query_id_t query_id; ulong col_access; #ifdef ERROR_INJECT_SUPPORT @@ -1723,11 +1637,6 @@ public: /* Statement id is thread-wide. This counter is used to generate ids */ ulong statement_id_counter; ulong rand_saved_seed1, rand_saved_seed2; - /* - Row counter, mainly for errors and warnings. Not increased in - create_sort_index(); may differ from examined_row_count. - */ - ulong row_count; pthread_t real_id; /* For debugging */ my_thread_id thread_id; uint tmp_table, global_read_lock; @@ -2031,8 +1940,8 @@ public: inline void clear_error() { DBUG_ENTER("clear_error"); - if (main_da.is_error()) - main_da.reset_diagnostics_area(); + if (stmt_da->is_error()) + stmt_da->reset_diagnostics_area(); is_slave_error= 0; DBUG_VOID_RETURN; } @@ -2064,7 +1973,7 @@ public: To raise this flag, use my_error(). */ - inline bool is_error() const { return main_da.is_error(); } + inline bool is_error() const { return stmt_da->is_error(); } inline CHARSET_INFO *charset() { return variables.character_set_client; } void update_charset(); @@ -2260,19 +2169,107 @@ public: void push_internal_handler(Internal_error_handler *handler); /** - Handle an error condition. - @param sql_errno the error number - @param level the error level - @return true if the error is handled + Handle a sql condition. + @param sql_errno the condition error number + @param sqlstate the condition sqlstate + @param level the condition level + @param msg the condition message text + @param[out] cond_hdl the sql condition raised, if any + @return true if the condition is handled */ - virtual bool handle_error(uint sql_errno, const char *message, - MYSQL_ERROR::enum_warning_level level); + virtual bool handle_condition(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl); /** Remove the error handler last pushed. */ void pop_internal_handler(); + /** + Raise an exception condition. + @param code the MYSQL_ERRNO error code of the error + */ + void raise_error(uint code); + + /** + Raise an exception condition, with a formatted message. + @param code the MYSQL_ERRNO error code of the error + */ + void raise_error_printf(uint code, ...); + + /** + Raise a completion condition (warning). + @param code the MYSQL_ERRNO error code of the warning + */ + void raise_warning(uint code); + + /** + Raise a completion condition (warning), with a formatted message. + @param code the MYSQL_ERRNO error code of the warning + */ + void raise_warning_printf(uint code, ...); + + /** + Raise a completion condition (note), with a fixed message. + @param code the MYSQL_ERRNO error code of the note + */ + void raise_note(uint code); + + /** + Raise an completion condition (note), with a formatted message. + @param code the MYSQL_ERRNO error code of the note + */ + void raise_note_printf(uint code, ...); + +private: + /* + Only the implementation of the SIGNAL and RESIGNAL statements + is permitted to raise SQL conditions in a generic way, + or to raise them by bypassing handlers (RESIGNAL). + To raise a SQL condition, the code should use the public + raise_error() or raise_warning() methods provided by class THD. + */ + friend class Signal_common; + friend class Signal_statement; + friend class Resignal_statement; + friend void push_warning(THD*, MYSQL_ERROR::enum_warning_level, uint, const char*); + friend void my_message_sql(uint, const char *, myf); + + /** + Raise a generic SQL condition. + @param sql_errno the condition error number + @param sqlstate the condition SQLSTATE + @param level the condition level + @param msg the condition message text + @return The condition raised, or NULL + */ + MYSQL_ERROR* + raise_condition(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg); + + /** + Raise a generic SQL condition, without activation any SQL condition + handlers. + This method is necessary to support the RESIGNAL statement, + which is allowed to bypass SQL exception handlers. + @param sql_errno the condition error number + @param sqlstate the condition SQLSTATE + @param level the condition level + @param msg the condition message text + @return The condition raised, or NULL + */ + MYSQL_ERROR* + raise_condition_no_handler(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg); + +public: /** Overloaded to guard query/query_length fields */ virtual void set_statement(Statement *stmt); @@ -2300,25 +2297,27 @@ private: tree itself is reused between executions and thus is stored elsewhere. */ MEM_ROOT main_mem_root; + Warning_info main_warning_info; + Diagnostics_area main_da; }; -/** A short cut for thd->main_da.set_ok_status(). */ +/** A short cut for thd->stmt_da->set_ok_status(). */ inline void -my_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0, +my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0, const char *message= NULL) { - thd->main_da.set_ok_status(thd, affected_rows, id, message); + thd->stmt_da->set_ok_status(thd, affected_rows, id, message); } -/** A short cut for thd->main_da.set_eof_status(). */ +/** A short cut for thd->stmt_da->set_eof_status(). */ inline void my_eof(THD *thd) { - thd->main_da.set_eof_status(thd); + thd->stmt_da->set_eof_status(thd); } #define tmp_disable_binlog(A) \ @@ -2986,11 +2985,11 @@ public: /* Bits in sql_command_flags */ -#define CF_CHANGES_DATA 1 -#define CF_HAS_ROW_COUNT 2 -#define CF_STATUS_COMMAND 4 -#define CF_SHOW_TABLE_COMMAND 8 -#define CF_WRITE_LOGS_COMMAND 16 +#define CF_CHANGES_DATA (1U << 0) +#define CF_HAS_ROW_COUNT (1U << 1) +#define CF_STATUS_COMMAND (1U << 2) +#define CF_SHOW_TABLE_COMMAND (1U << 3) +#define CF_WRITE_LOGS_COMMAND (1U << 4) /** Must be set for SQL statements that may contain Item expressions and/or use joins and tables. @@ -3004,7 +3003,17 @@ public: reprepare. Consequently, complex item expressions and joins are currently prohibited in these statements. */ -#define CF_REEXECUTION_FRAGILE 32 +#define CF_REEXECUTION_FRAGILE (1U << 5) + +/** + Diagnostic statement. + Diagnostic statements: + - SHOW WARNING + - SHOW ERROR + - GET DIAGNOSTICS (WL#2111) + do not modify the diagnostics area during execution. +*/ +#define CF_DIAGNOSTIC_STMT (1U << 8) /* Functions in sql_class.cc */ diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 3952567c329..404d734559f 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1001,7 +1001,7 @@ static void end_connection(THD *thd) thd->thread_id,(thd->db ? thd->db : "unconnected"), sctx->user ? sctx->user : "unauthenticated", sctx->host_or_ip, - (thd->main_da.is_error() ? thd->main_da.message() : + (thd->stmt_da->is_error() ? thd->stmt_da->message() : ER(ER_UNKNOWN_ERROR))); } } @@ -1046,7 +1046,7 @@ static void prepare_new_connection_state(THD* thd) thd->thread_id,(thd->db ? thd->db : "unconnected"), sctx->user ? sctx->user : "unauthenticated", sctx->host_or_ip, "init_connect command failed"); - sql_print_warning("%s", thd->main_da.message()); + sql_print_warning("%s", thd->stmt_da->message()); } thd->proc_info=0; thd->set_time(); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 37adf5c403a..9b747759ece 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -178,9 +178,9 @@ exit: if (orig_table_list->view) { if (thd->is_error() && - (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR || - thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION || - thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST)) + (thd->stmt_da->sql_errno() == ER_BAD_FIELD_ERROR || + thd->stmt_da->sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION || + thd->stmt_da->sql_errno() == ER_SP_DOES_NOT_EXIST)) { thd->clear_error(); my_error(ER_VIEW_INVALID, MYF(0), orig_table_list->db, diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 9ea7facbe41..2837e45fb47 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -1,4 +1,5 @@ -/* Copyright (C) 1995-2002 MySQL AB +/* Copyright (C) 1995-2002 MySQL AB, + Copyright (C) 2008-2009 Sun Microsystems, Inc 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 @@ -42,133 +43,577 @@ This file contains the implementation of error and warnings related ***********************************************************************/ #include "mysql_priv.h" +#include "sql_error.h" #include "sp_rcontext.h" /* - Store a new message in an error object + Design notes about MYSQL_ERROR::m_message_text. - This is used to in group_concat() to register how many warnings we actually - got after the query has been executed. + The member MYSQL_ERROR::m_message_text contains the text associated with + an error, warning or note (which are all SQL 'conditions') + + Producer of MYSQL_ERROR::m_message_text: + ---------------------------------------- + + (#1) the server implementation itself, when invoking functions like + my_error() or push_warning() + + (#2) user code in stored programs, when using the SIGNAL statement. + + (#3) user code in stored programs, when using the RESIGNAL statement. + + When invoking my_error(), the error number and message is typically + provided like this: + - my_error(ER_WRONG_DB_NAME, MYF(0), ...); + - my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); + + In both cases, the message is retrieved from ER(ER_XXX), which in turn + is read from the resource file errmsg.sys at server startup. + The strings stored in the errmsg.sys file are expressed in the character set + that corresponds to the server --language start option + (see error_message_charset_info). + + When executing: + - a SIGNAL statement, + - a RESIGNAL statement, + the message text is provided by the user logic, and is expressed in UTF8. + + Storage of MYSQL_ERROR::m_message_text: + --------------------------------------- + + (#4) The class MYSQL_ERROR is used to hold the message text member. + This class represents a single SQL condition. + + (#5) The class Warning_info represents a SQL condition area, and contains + a collection of SQL conditions in the Warning_info::m_warn_list + + Consumer of MYSQL_ERROR::m_message_text: + ---------------------------------------- + + (#6) The statements SHOW WARNINGS and SHOW ERRORS display the content of + the warning list. + + (#7) The GET DIAGNOSTICS statement (planned, not implemented yet) will + also read the content of: + - the top level statement condition area (when executed in a query), + - a sub statement (when executed in a stored program) + and return the data stored in a MYSQL_ERROR. + + (#8) The RESIGNAL statement reads the MYSQL_ERROR caught by an exception + handler, to raise a new or modified condition (in #3). + + The big picture + --------------- + -------------- + | ^ + V | + my_error(#1) SIGNAL(#2) RESIGNAL(#3) | + |(#A) |(#B) |(#C) | + | | | | + ----------------------------|---------------------------- | + | | + V | + MYSQL_ERROR(#4) | + | | + | | + V | + Warning_info(#5) | + | | + ----------------------------------------------------- | + | | | | + | | | | + | | | | + V V V | + SHOW WARNINGS(#6) GET DIAGNOSTICS(#7) RESIGNAL(#8) | + | | | | | + | -------- | V | + | | | -------------- + V | | + Connectors | | + | | | + ------------------------- + | + V + Client application + + Current implementation status + ----------------------------- + + (#1) (my_error) produces data in the 'error_message_charset_info' CHARSET + + (#2) and (#3) (SIGNAL, RESIGNAL) produces data internally in UTF8 + + (#6) (SHOW WARNINGS) produces data in the 'error_message_charset_info' CHARSET + + (#7) (GET DIAGNOSTICS) is not implemented. + + (#8) (RESIGNAL) produces data internally in UTF8 (see #3) + + As a result, the design choice for (#4) and (#5) is to store data in + the 'error_message_charset_info' CHARSET, to minimize impact on the code base. + This is implemented by using 'String MYSQL_ERROR::m_message_text'. + + The UTF8 -> error_message_charset_info conversion is implemented in + Signal_common::eval_signal_informations() (for path #B and #C). + + Future work + ----------- + + - Change (#1) (my_error) to generate errors in UTF8. + See WL#751 (Recoding of error messages) + + - Change (#4 and #5) to store message text in UTF8 natively. + In practice, this means changing the type of the message text to + ' MYSQL_ERROR::m_message_text', and is a direct + consequence of WL#751. + + - Implement (#9) (GET DIAGNOSTICS). + See WL#2111 (Stored Procedures: Implement GET DIAGNOSTICS) */ -void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg) +MYSQL_ERROR::MYSQL_ERROR() + : Sql_alloc(), + m_class_origin((const char*) NULL, 0, & my_charset_utf8_bin), + m_subclass_origin((const char*) NULL, 0, & my_charset_utf8_bin), + m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8_bin), + m_constraint_schema((const char*) NULL, 0, & my_charset_utf8_bin), + m_constraint_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_catalog_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_schema_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_table_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_column_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_message_text(), + m_sql_errno(0), + m_level(MYSQL_ERROR::WARN_LEVEL_ERROR), + m_mem_root(NULL) { - msg= strdup_root(&thd->warn_root, msg_arg); + memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate)); } - -/* - Reset all warnings for the thread - - SYNOPSIS - mysql_reset_errors() - thd Thread handle - force Reset warnings even if it has been done before - - IMPLEMENTATION - Don't reset warnings if this has already been called for this query. - This may happen if one gets a warning during the parsing stage, - in which case push_warnings() has already called this function. -*/ - -void mysql_reset_errors(THD *thd, bool force) +void MYSQL_ERROR::init(MEM_ROOT *mem_root) { - DBUG_ENTER("mysql_reset_errors"); - if (thd->query_id != thd->warn_id || force) + DBUG_ASSERT(mem_root != NULL); + DBUG_ASSERT(m_mem_root == NULL); + m_mem_root= mem_root; +} + +void MYSQL_ERROR::clear() +{ + m_class_origin.length(0); + m_subclass_origin.length(0); + m_constraint_catalog.length(0); + m_constraint_schema.length(0); + m_constraint_name.length(0); + m_catalog_name.length(0); + m_schema_name.length(0); + m_table_name.length(0); + m_column_name.length(0); + m_cursor_name.length(0); + m_message_text.length(0); + m_sql_errno= 0; + m_level= MYSQL_ERROR::WARN_LEVEL_ERROR; +} + +MYSQL_ERROR::MYSQL_ERROR(MEM_ROOT *mem_root) + : Sql_alloc(), + m_class_origin((const char*) NULL, 0, & my_charset_utf8_bin), + m_subclass_origin((const char*) NULL, 0, & my_charset_utf8_bin), + m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8_bin), + m_constraint_schema((const char*) NULL, 0, & my_charset_utf8_bin), + m_constraint_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_catalog_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_schema_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_table_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_column_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin), + m_message_text(), + m_sql_errno(0), + m_level(MYSQL_ERROR::WARN_LEVEL_ERROR), + m_mem_root(mem_root) +{ + DBUG_ASSERT(mem_root != NULL); + memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate)); +} + +static void copy_string(MEM_ROOT *mem_root, String* dst, const String* src) +{ + size_t len= src->length(); + if (len) { - thd->warn_id= thd->query_id; - free_root(&thd->warn_root,MYF(0)); - bzero((char*) thd->warn_count, sizeof(thd->warn_count)); - if (force) - thd->total_warn_count= 0; - thd->warn_list.empty(); - thd->row_count= 1; // by default point to row 1 + char* copy= (char*) alloc_root(mem_root, len + 1); + if (copy) + { + memcpy(copy, src->ptr(), len); + copy[len]= '\0'; + dst->set(copy, len, src->charset()); + } } + else + dst->length(0); +} + +void +MYSQL_ERROR::copy_opt_attributes(const MYSQL_ERROR *cond) +{ + DBUG_ASSERT(this != cond); + copy_string(m_mem_root, & m_class_origin, & cond->m_class_origin); + copy_string(m_mem_root, & m_subclass_origin, & cond->m_subclass_origin); + copy_string(m_mem_root, & m_constraint_catalog, & cond->m_constraint_catalog); + copy_string(m_mem_root, & m_constraint_schema, & cond->m_constraint_schema); + copy_string(m_mem_root, & m_constraint_name, & cond->m_constraint_name); + copy_string(m_mem_root, & m_catalog_name, & cond->m_catalog_name); + copy_string(m_mem_root, & m_schema_name, & cond->m_schema_name); + copy_string(m_mem_root, & m_table_name, & cond->m_table_name); + copy_string(m_mem_root, & m_column_name, & cond->m_column_name); + copy_string(m_mem_root, & m_cursor_name, & cond->m_cursor_name); +} + +void +MYSQL_ERROR::set(uint sql_errno, const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, const char* msg) +{ + DBUG_ASSERT(sql_errno != 0); + DBUG_ASSERT(sqlstate != NULL); + DBUG_ASSERT(msg != NULL); + + m_sql_errno= sql_errno; + memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH); + m_returned_sqlstate[SQLSTATE_LENGTH]= '\0'; + + set_builtin_message_text(msg); + m_level= level; +} + +void +MYSQL_ERROR::set_builtin_message_text(const char* str) +{ + /* + See the comments + "Design notes about MYSQL_ERROR::m_message_text." + */ + const char* copy; + + copy= strdup_root(m_mem_root, str); + m_message_text.set(copy, strlen(copy), error_message_charset_info); + DBUG_ASSERT(! m_message_text.is_alloced()); +} + +const char* +MYSQL_ERROR::get_message_text() const +{ + return m_message_text.ptr(); +} + +int +MYSQL_ERROR::get_message_octet_length() const +{ + return m_message_text.length(); +} + +void +MYSQL_ERROR::set_sqlstate(const char* sqlstate) +{ + memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH); + m_returned_sqlstate[SQLSTATE_LENGTH]= '\0'; +} + +/** + Clear this diagnostics area. + + Normally called at the end of a statement. +*/ + +void +Diagnostics_area::reset_diagnostics_area() +{ + DBUG_ENTER("reset_diagnostics_area"); +#ifdef DBUG_OFF + can_overwrite_status= FALSE; + /** Don't take chances in production */ + m_message[0]= '\0'; + m_sql_errno= 0; + m_server_status= 0; + m_affected_rows= 0; + m_last_insert_id= 0; + m_statement_warn_count= 0; +#endif + is_sent= FALSE; + /** Tiny reset in debug mode to see garbage right away */ + m_status= DA_EMPTY; DBUG_VOID_RETURN; } -/* - Push the warning/error to error list if there is still room in the list +/** + Set OK status -- ends commands that do not return a + result set, e.g. INSERT/UPDATE/DELETE. +*/ + +void +Diagnostics_area::set_ok_status(THD *thd, ulonglong affected_rows_arg, + ulonglong last_insert_id_arg, + const char *message_arg) +{ + DBUG_ENTER("set_ok_status"); + DBUG_ASSERT(! is_set()); + /* + In production, refuse to overwrite an error or a custom response + with an OK packet. + */ + if (is_error() || is_disabled()) + return; + + m_server_status= thd->server_status; + m_statement_warn_count= thd->warning_info->statement_warn_count(); + m_affected_rows= affected_rows_arg; + m_last_insert_id= last_insert_id_arg; + if (message_arg) + strmake(m_message, message_arg, sizeof(m_message) - 1); + else + m_message[0]= '\0'; + m_status= DA_OK; + DBUG_VOID_RETURN; +} + + +/** + Set EOF status. +*/ + +void +Diagnostics_area::set_eof_status(THD *thd) +{ + DBUG_ENTER("set_eof_status"); + /* Only allowed to report eof if has not yet reported an error */ + DBUG_ASSERT(! is_set()); + /* + In production, refuse to overwrite an error or a custom response + with an EOF packet. + */ + if (is_error() || is_disabled()) + return; + + m_server_status= thd->server_status; + /* + If inside a stored procedure, do not return the total + number of warnings, since they are not available to the client + anyway. + */ + m_statement_warn_count= (thd->spcont ? + 0 : thd->warning_info->statement_warn_count()); + + m_status= DA_EOF; + DBUG_VOID_RETURN; +} + +/** + Set ERROR status. +*/ + +void +Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg, + const char *message_arg, + const char *sqlstate) +{ + DBUG_ENTER("set_error_status"); + /* + Only allowed to report error if has not yet reported a success + The only exception is when we flush the message to the client, + an error can happen during the flush. + */ + DBUG_ASSERT(! is_set() || can_overwrite_status); +#ifdef DBUG_OFF + /* + In production, refuse to overwrite a custom response with an + ERROR packet. + */ + if (is_disabled()) + return; +#endif + + if (sqlstate == NULL) + sqlstate= mysql_errno_to_sqlstate(sql_errno_arg); + + m_sql_errno= sql_errno_arg; + memcpy(m_sqlstate, sqlstate, SQLSTATE_LENGTH); + m_sqlstate[SQLSTATE_LENGTH]= '\0'; + strmake(m_message, message_arg, sizeof(m_message)-1); + + m_status= DA_ERROR; + DBUG_VOID_RETURN; +} + + +/** + Mark the diagnostics area as 'DISABLED'. + + This is used in rare cases when the COM_ command at hand sends a response + in a custom format. One example is the query cache, another is + COM_STMT_PREPARE. +*/ + +void +Diagnostics_area::disable_status() +{ + DBUG_ASSERT(! is_set()); + m_status= DA_DISABLED; +} + +Warning_info::Warning_info(ulonglong warn_id_arg) + :m_statement_warn_count(0), + m_current_row_for_warning(1), + m_warn_id(warn_id_arg), + m_read_only(FALSE) +{ + /* Initialize sub structures */ + init_sql_alloc(&m_warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); + m_warn_list.empty(); + bzero((char*) m_warn_count, sizeof(m_warn_count)); +} + + +Warning_info::~Warning_info() +{ + free_root(&m_warn_root,MYF(0)); +} + + +/** + Reset the warning information of this connection. +*/ + +void Warning_info::clear_warning_info(ulonglong warn_id_arg) +{ + m_warn_id= warn_id_arg; + free_root(&m_warn_root, MYF(0)); + bzero((char*) m_warn_count, sizeof(m_warn_count)); + m_warn_list.empty(); + m_statement_warn_count= 0; + m_current_row_for_warning= 1; /* Start counting from the first row */ +} + +void Warning_info::reserve_space(THD *thd, uint count) +{ + /* Make room for count conditions */ + while ((m_warn_list.elements > 0) && + ((m_warn_list.elements + count) > thd->variables.max_error_count)) + m_warn_list.pop(); +} + +/** + Append warnings only if the original contents of the routine + warning info was replaced. +*/ +void Warning_info::merge_with_routine_info(THD *thd, Warning_info *source) +{ + /* + If a routine body is empty or if a routine did not + generate any warnings (thus m_warn_id didn't change), + do not duplicate our own contents by appending the + contents of the called routine. We know that the called + routine did not change its warning info. + + On the other hand, if the routine body is not empty and + some statement in the routine generates a warning or + uses tables, m_warn_id is guaranteed to have changed. + In this case we know that the routine warning info + contains only new warnings, and thus we perform a copy. + */ + if (m_warn_id != source->m_warn_id) + { + /* + If the invocation of the routine was a standalone statement, + rather than a sub-statement, in other words, if it's a CALL + of a procedure, rather than invocation of a function or a + trigger, we need to clear the current contents of the caller's + warning info. + + This is per MySQL rules: if a statement generates a warning, + warnings from the previous statement are flushed. Normally + it's done in push_warning(). However, here we don't use + push_warning() to avoid invocation of condition handlers or + escalation of warnings to errors. + */ + opt_clear_warning_info(thd->query_id); + append_warning_info(thd, source); + } +} + +/** + Add a warning to the list of warnings. Increment the respective + counters. +*/ +MYSQL_ERROR *Warning_info::push_warning(THD *thd, + uint sql_errno, const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char *msg) +{ + MYSQL_ERROR *cond= NULL; + + if (! m_read_only) + { + if (m_warn_list.elements < thd->variables.max_error_count) + { + cond= new (& m_warn_root) MYSQL_ERROR(& m_warn_root); + if (cond) + { + cond->set(sql_errno, sqlstate, level, msg); + m_warn_list.push_back(cond, &m_warn_root); + } + } + m_warn_count[(uint) level]++; + } + + m_statement_warn_count++; + return cond; +} + +/* + Push the warning to error list if there is still room in the list SYNOPSIS push_warning() thd Thread handle - level Severity of warning (note, warning, error ...) + level Severity of warning (note, warning) code Error number msg Clear error message - - RETURN - pointer on MYSQL_ERROR object */ -MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, - uint code, const char *msg) +void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, + uint code, const char *msg) { - MYSQL_ERROR *err= 0; DBUG_ENTER("push_warning"); DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg)); - DBUG_ASSERT(code != 0); - DBUG_ASSERT(msg != NULL); + /* + Calling push_warning/push_warning_printf with a + level of WARN_LEVEL_ERROR *is* a bug. + Either use my_error(), or WARN_LEVEL_WARN. + Please fix the calling code, and do *NOT* + add more work around code in the assert below. + */ + DBUG_ASSERT( (level != MYSQL_ERROR::WARN_LEVEL_ERROR) + || (code == ER_CANT_CREATE_TABLE) /* See Bug#47233 */ + || (code == ER_ILLEGAL_HA_CREATE_OPTION) /* See Bug#47233 */ + ); - if (level == MYSQL_ERROR::WARN_LEVEL_NOTE && - !(thd->options & OPTION_SQL_NOTES)) - DBUG_RETURN(0); + if (level == MYSQL_ERROR::WARN_LEVEL_ERROR) + level= MYSQL_ERROR::WARN_LEVEL_WARN; - if (thd->query_id != thd->warn_id && !thd->spcont) - mysql_reset_errors(thd, 0); - thd->got_warning= 1; + (void) thd->raise_condition(code, NULL, level, msg); - /* Abort if we are using strict mode and we are not using IGNORE */ - if ((int) level >= (int) MYSQL_ERROR::WARN_LEVEL_WARN && - thd->really_abort_on_warning()) - { - /* Avoid my_message() calling push_warning */ - bool no_warnings_for_error= thd->no_warnings_for_error; - sp_rcontext *spcont= thd->spcont; - - thd->no_warnings_for_error= 1; - thd->spcont= NULL; - - thd->killed= THD::KILL_BAD_DATA; - my_message(code, msg, MYF(0)); - - thd->spcont= spcont; - thd->no_warnings_for_error= no_warnings_for_error; - /* Store error in error list (as my_message() didn't do it) */ - level= MYSQL_ERROR::WARN_LEVEL_ERROR; - } - - if (thd->handle_error(code, msg, level)) - DBUG_RETURN(NULL); - - if (thd->spcont && - thd->spcont->handle_error(code, level, thd)) - { - DBUG_RETURN(NULL); - } - query_cache_abort(&thd->net); - - - if (thd->warn_list.elements < thd->variables.max_error_count) - { - /* We have to use warn_root, as mem_root is freed after each query */ - if ((err= new (&thd->warn_root) MYSQL_ERROR(thd, code, level, msg))) - thd->warn_list.push_back(err, &thd->warn_root); - } - thd->warn_count[(uint) level]++; - thd->total_warn_count++; - DBUG_RETURN(err); + DBUG_VOID_RETURN; } + /* - Push the warning/error to error list if there is still room in the list + Push the warning to error list if there is still room in the list SYNOPSIS push_warning_printf() thd Thread handle - level Severity of warning (note, warning, error ...) + level Severity of warning (note, warning) code Error number msg Clear error message */ @@ -217,10 +662,12 @@ const LEX_STRING warning_level_names[]= }; bool mysqld_show_warnings(THD *thd, ulong levels_to_show) -{ +{ List field_list; DBUG_ENTER("mysqld_show_warnings"); + DBUG_ASSERT(thd->warning_info->is_read_only()); + field_list.push_back(new Item_empty_string("Level", 7)); field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG)); field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE)); @@ -232,29 +679,36 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show) MYSQL_ERROR *err; SELECT_LEX *sel= &thd->lex->select_lex; SELECT_LEX_UNIT *unit= &thd->lex->unit; - ha_rows idx= 0; + ulonglong idx= 0; Protocol *protocol=thd->protocol; unit->set_limit(sel); - List_iterator_fast it(thd->warn_list); + List_iterator_fast it(thd->warning_info->warn_list()); while ((err= it++)) { /* Skip levels that the user is not interested in */ - if (!(levels_to_show & ((ulong) 1 << err->level))) + if (!(levels_to_show & ((ulong) 1 << err->get_level()))) continue; if (++idx <= unit->offset_limit_cnt) continue; if (idx > unit->select_limit_cnt) break; protocol->prepare_for_resend(); - protocol->store(warning_level_names[err->level].str, - warning_level_names[err->level].length, system_charset_info); - protocol->store((uint32) err->code); - protocol->store(err->msg, (uint) strlen(err->msg), system_charset_info); + protocol->store(warning_level_names[err->get_level()].str, + warning_level_names[err->get_level()].length, + system_charset_info); + protocol->store((uint32) err->get_sql_errno()); + protocol->store(err->get_message_text(), + err->get_message_octet_length(), + system_charset_info); if (protocol->write()) DBUG_RETURN(TRUE); } my_eof(thd); + + thd->warning_info->set_read_only(FALSE); + DBUG_RETURN(FALSE); } + diff --git a/sql/sql_error.h b/sql/sql_error.h index f98264dce50..f7b0ff56efa 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, + Copyright (C) 2008-2009 Sun Microsystems, Inc 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 @@ -13,31 +14,514 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -class MYSQL_ERROR: public Sql_alloc +#ifndef SQL_ERROR_H +#define SQL_ERROR_H + +#include "sql_list.h" /* Sql_alloc, MEM_ROOT */ +#include "m_string.h" /* LEX_STRING */ +#include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */ + +class THD; + +/** + Stores status of the currently executed statement. + Cleared at the beginning of the statement, and then + can hold either OK, ERROR, or EOF status. + Can not be assigned twice per statement. +*/ + +class Diagnostics_area { public: - enum enum_warning_level - { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; - - uint code; - enum_warning_level level; - char *msg; - - MYSQL_ERROR(THD *thd, uint code_arg, enum_warning_level level_arg, - const char *msg_arg) - :code(code_arg), level(level_arg) + enum enum_diagnostics_status { - if (msg_arg) - set_msg(thd, msg_arg); + /** The area is cleared at start of a statement. */ + DA_EMPTY= 0, + /** Set whenever one calls my_ok(). */ + DA_OK, + /** Set whenever one calls my_eof(). */ + DA_EOF, + /** Set whenever one calls my_error() or my_message(). */ + DA_ERROR, + /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */ + DA_DISABLED + }; + /** True if status information is sent to the client. */ + bool is_sent; + /** Set to make set_error_status after set_{ok,eof}_status possible. */ + bool can_overwrite_status; + + void set_ok_status(THD *thd, ulonglong affected_rows_arg, + ulonglong last_insert_id_arg, + const char *message); + void set_eof_status(THD *thd); + void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg, + const char *sqlstate); + + void disable_status(); + + void reset_diagnostics_area(); + + bool is_set() const { return m_status != DA_EMPTY; } + bool is_error() const { return m_status == DA_ERROR; } + bool is_eof() const { return m_status == DA_EOF; } + bool is_ok() const { return m_status == DA_OK; } + bool is_disabled() const { return m_status == DA_DISABLED; } + enum_diagnostics_status status() const { return m_status; } + + const char *message() const + { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; } + + uint sql_errno() const + { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; } + + const char* get_sqlstate() const + { DBUG_ASSERT(m_status == DA_ERROR); return m_sqlstate; } + + uint server_status() const + { + DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF); + return m_server_status; } - void set_msg(THD *thd, const char *msg_arg); + + ulonglong affected_rows() const + { DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; } + + ulonglong last_insert_id() const + { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; } + + uint statement_warn_count() const + { + DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF); + return m_statement_warn_count; + } + + Diagnostics_area() { reset_diagnostics_area(); } + +private: + /** Message buffer. Can be used by OK or ERROR status. */ + char m_message[MYSQL_ERRMSG_SIZE]; + /** + SQL error number. One of ER_ codes from share/errmsg.txt. + Set by set_error_status. + */ + uint m_sql_errno; + + char m_sqlstate[SQLSTATE_LENGTH+1]; + + /** + Copied from thd->server_status when the diagnostics area is assigned. + We need this member as some places in the code use the following pattern: + thd->server_status|= ... + my_eof(thd); + thd->server_status&= ~... + Assigned by OK, EOF or ERROR. + */ + uint m_server_status; + /** + The number of rows affected by the last statement. This is + semantically close to thd->row_count_func, but has a different + life cycle. thd->row_count_func stores the value returned by + function ROW_COUNT() and is cleared only by statements that + update its value, such as INSERT, UPDATE, DELETE and few others. + This member is cleared at the beginning of the next statement. + + We could possibly merge the two, but life cycle of thd->row_count_func + can not be changed. + */ + ulonglong m_affected_rows; + /** + Similarly to the previous member, this is a replacement of + thd->first_successful_insert_id_in_prev_stmt, which is used + to implement LAST_INSERT_ID(). + */ + ulonglong m_last_insert_id; + /** + Number of warnings of this last statement. May differ from + the number of warnings returned by SHOW WARNINGS e.g. in case + the statement doesn't clear the warnings, and doesn't generate + them. + */ + uint m_statement_warn_count; + enum_diagnostics_status m_status; }; -MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, - uint code, const char *msg); +/////////////////////////////////////////////////////////////////////////// + +/** + Representation of a SQL condition. + A SQL condition can be a completion condition (note, warning), + or an exception condition (error, not found). + @note This class is named MYSQL_ERROR instead of SQL_condition for historical reasons, + to facilitate merging code with previous releases. +*/ +class MYSQL_ERROR : public Sql_alloc +{ +public: + /* + Enumeration value describing the severity of the error. + + Note that these enumeration values must correspond to the indices + of the sql_print_message_handlers array. + */ + enum enum_warning_level + { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; + /** + Get the MESSAGE_TEXT of this condition. + @return the message text. + */ + const char* get_message_text() const; + + /** + Get the MESSAGE_OCTET_LENGTH of this condition. + @return the length in bytes of the message text. + */ + int get_message_octet_length() const; + + /** + Get the SQLSTATE of this condition. + @return the sql state. + */ + const char* get_sqlstate() const + { return m_returned_sqlstate; } + + /** + Get the SQL_ERRNO of this condition. + @return the sql error number condition item. + */ + uint get_sql_errno() const + { return m_sql_errno; } + + /** + Get the error level of this condition. + @return the error level condition item. + */ + MYSQL_ERROR::enum_warning_level get_level() const + { return m_level; } + +private: + /* + The interface of MYSQL_ERROR is mostly private, by design, + so that only the following code: + - various raise_error() or raise_warning() methods in class THD, + - the implementation of SIGNAL / RESIGNAL + - catch / re-throw of SQL conditions in stored procedures (sp_rcontext) + is allowed to create / modify a SQL condition. + Enforcing this policy prevents confusion, since the only public + interface available to the rest of the server implementation + is the interface offered by the THD methods (THD::raise_error()), + which should be used. + */ + friend class THD; + friend class Warning_info; + friend class Signal_common; + friend class Signal_statement; + friend class Resignal_statement; + friend class sp_rcontext; + + /** + Default constructor. + This constructor is usefull when allocating arrays. + Note that the init() method should be called to complete the MYSQL_ERROR. + */ + MYSQL_ERROR(); + + /** + Complete the MYSQL_ERROR initialisation. + @param mem_root The memory root to use for the condition items + of this condition + */ + void init(MEM_ROOT *mem_root); + + /** + Constructor. + @param mem_root The memory root to use for the condition items + of this condition + */ + MYSQL_ERROR(MEM_ROOT *mem_root); + + /** Destructor. */ + ~MYSQL_ERROR() + {} + + /** + Copy optional condition items attributes. + @param cond the condition to copy. + */ + void copy_opt_attributes(const MYSQL_ERROR *cond); + + /** + Set this condition area with a fixed message text. + @param thd the current thread. + @param code the error number for this condition. + @param str the message text for this condition. + @param level the error level for this condition. + @param MyFlags additional flags. + */ + void set(uint sql_errno, const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg); + + /** + Set the condition message test. + @param str Message text, expressed in the character set derived from + the server --language option + */ + void set_builtin_message_text(const char* str); + + /** Set the SQLSTATE of this condition. */ + void set_sqlstate(const char* sqlstate); + + /** + Clear this SQL condition. + */ + void clear(); + +private: + /** SQL CLASS_ORIGIN condition item. */ + String m_class_origin; + + /** SQL SUBCLASS_ORIGIN condition item. */ + String m_subclass_origin; + + /** SQL CONSTRAINT_CATALOG condition item. */ + String m_constraint_catalog; + + /** SQL CONSTRAINT_SCHEMA condition item. */ + String m_constraint_schema; + + /** SQL CONSTRAINT_NAME condition item. */ + String m_constraint_name; + + /** SQL CATALOG_NAME condition item. */ + String m_catalog_name; + + /** SQL SCHEMA_NAME condition item. */ + String m_schema_name; + + /** SQL TABLE_NAME condition item. */ + String m_table_name; + + /** SQL COLUMN_NAME condition item. */ + String m_column_name; + + /** SQL CURSOR_NAME condition item. */ + String m_cursor_name; + + /** Message text, expressed in the character set implied by --language. */ + String m_message_text; + + /** MySQL extension, MYSQL_ERRNO condition item. */ + uint m_sql_errno; + + /** + SQL RETURNED_SQLSTATE condition item. + This member is always NUL terminated. + */ + char m_returned_sqlstate[SQLSTATE_LENGTH+1]; + + /** Severity (error, warning, note) of this condition. */ + MYSQL_ERROR::enum_warning_level m_level; + + /** Memory root to use to hold condition item values. */ + MEM_ROOT *m_mem_root; +}; + +/////////////////////////////////////////////////////////////////////////// + +/** + Information about warnings of the current connection. +*/ + +class Warning_info +{ + /** A memory root to allocate warnings and errors */ + MEM_ROOT m_warn_root; + /** List of warnings of all severities (levels). */ + List m_warn_list; + /** A break down of the number of warnings per severity (level). */ + uint m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; + /** + The number of warnings of the current statement. Warning_info + life cycle differs from statement life cycle -- it may span + multiple statements. In that case we get + m_statement_warn_count 0, whereas m_warn_list is not empty. + */ + uint m_statement_warn_count; + /* + Row counter, to print in errors and warnings. Not increased in + create_sort_index(); may differ from examined_row_count. + */ + ulong m_current_row_for_warning; + /** Used to optionally clear warnings only once per statement. */ + ulonglong m_warn_id; + +private: + Warning_info(const Warning_info &rhs); /* Not implemented */ + Warning_info& operator=(const Warning_info &rhs); /* Not implemented */ +public: + + Warning_info(ulonglong warn_id_arg); + ~Warning_info(); + + /** + Reset the warning information. Clear all warnings, + the number of warnings, reset current row counter + to point to the first row. + */ + void clear_warning_info(ulonglong warn_id_arg); + /** + Only clear warning info if haven't yet done that already + for the current query. Allows to be issued at any time + during the query, without risk of clearing some warnings + that have been generated by the current statement. + + @todo: This is a sign of sloppy coding. Instead we need to + designate one place in a statement life cycle where we call + clear_warning_info(). + */ + void opt_clear_warning_info(ulonglong query_id) + { + if (query_id != m_warn_id) + clear_warning_info(query_id); + } + + void append_warning_info(THD *thd, Warning_info *source) + { + append_warnings(thd, & source->warn_list()); + } + + /** + Concatenate the list of warnings. + It's considered tolerable to lose a warning. + */ + void append_warnings(THD *thd, List *src) + { + MYSQL_ERROR *err; + MYSQL_ERROR *copy; + List_iterator_fast it(*src); + /* + Don't use ::push_warning() to avoid invocation of condition + handlers or escalation of warnings to errors. + */ + while ((err= it++)) + { + copy= Warning_info::push_warning(thd, err->get_sql_errno(), err->get_sqlstate(), + err->get_level(), err->get_message_text()); + if (copy) + copy->copy_opt_attributes(err); + } + } + + /** + Conditional merge of related warning information areas. + */ + void merge_with_routine_info(THD *thd, Warning_info *source); + + /** + Reset between two COM_ commands. Warnings are preserved + between commands, but statement_warn_count indicates + the number of warnings of this particular statement only. + */ + void reset_for_next_command() { m_statement_warn_count= 0; } + + /** + Used for @@warning_count system variable, which prints + the number of rows returned by SHOW WARNINGS. + */ + ulong warn_count() const + { + /* + This may be higher than warn_list.elements if we have + had more warnings than thd->variables.max_error_count. + */ + return (m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] + + m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] + + m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]); + } + + /** + This is for iteration purposes. We return a non-constant reference + since List doesn't have constant iterators. + */ + List &warn_list() { return m_warn_list; } + + /** + The number of errors, or number of rows returned by SHOW ERRORS, + also the value of session variable @@error_count. + */ + ulong error_count() const + { + return m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR]; + } + + /** Id of the warning information area. */ + ulonglong warn_id() const { return m_warn_id; } + + /** Do we have any errors and warnings that we can *show*? */ + bool is_empty() const { return m_warn_list.elements == 0; } + + /** Increment the current row counter to point at the next row. */ + void inc_current_row_for_warning() { m_current_row_for_warning++; } + /** Reset the current row counter. Start counting from the first row. */ + void reset_current_row_for_warning() { m_current_row_for_warning= 1; } + /** Return the current counter value. */ + ulong current_row_for_warning() const { return m_current_row_for_warning; } + + ulong statement_warn_count() const { return m_statement_warn_count; } + + /** + Reserve some space in the condition area. + This is a privileged operation, reserved for the RESIGNAL implementation, + as only the RESIGNAL statement is allowed to remove conditions from + the condition area. + For other statements, new conditions are not added to the condition + area once the condition area is full. + @param thd The current thread + @param count The number of slots to reserve + */ + void reserve_space(THD *thd, uint count); + + /** Add a new condition to the current list. */ + MYSQL_ERROR *push_warning(THD *thd, + uint sql_errno, const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg); + + /** + Set the read only status for this statement area. + This is a privileged operation, reserved for the implementation of + diagnostics related statements, to enforce that the statement area is + left untouched during execution. + The diagnostics statements are: + - SHOW WARNINGS + - SHOW ERRORS + - GET DIAGNOSTICS + @param read_only the read only property to set + */ + void set_read_only(bool read_only) + { m_read_only= read_only; } + + /** + Read only status. + @return the read only property + */ + bool is_read_only() const + { return m_read_only; } + +private: + /** Read only status. */ + bool m_read_only; + + friend class Resignal_statement; +}; + +void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, + uint code, const char *msg); void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, const char *format, ...); -void mysql_reset_errors(THD *thd, bool force); bool mysqld_show_warnings(THD *thd, ulong levels_to_show); extern const LEX_STRING warning_level_names[]; + +#endif // SQL_ERROR_H diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index cda97ffe521..df5e3506f4b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -810,7 +810,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, error=write_record(thd, table ,&info); if (error) break; - thd->row_count++; + thd->warning_info->inc_current_row_for_warning(); } free_underlaid_joins(thd, &thd->lex->select_lex); @@ -949,10 +949,12 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (ignore) sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, (lock_type == TL_WRITE_DELAYED) ? (ulong) 0 : - (ulong) (info.records - info.copied), (ulong) thd->cuted_fields); + (ulong) (info.records - info.copied), + (ulong) thd->warning_info->statement_warn_count()); else sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, - (ulong) (info.deleted + updated), (ulong) thd->cuted_fields); + (ulong) (info.deleted + updated), + (ulong) thd->warning_info->statement_warn_count()); thd->row_count_func= info.copied + info.deleted + updated; ::my_ok(thd, (ulong) thd->row_count_func, id, buff); } @@ -1955,7 +1957,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) main thread. Use of my_message will enable stored procedures continue handlers. */ - my_message(di->thd.main_da.sql_errno(), di->thd.main_da.message(), + my_message(di->thd.stmt_da->sql_errno(), di->thd.stmt_da->message(), MYF(0)); } di->unlock(); @@ -2032,7 +2034,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) goto error; if (dead) { - my_message(thd.main_da.sql_errno(), thd.main_da.message(), MYF(0)); + my_message(thd.stmt_da->sql_errno(), thd.stmt_da->message(), MYF(0)); goto error; } } @@ -2305,8 +2307,8 @@ pthread_handler_t handle_delayed_insert(void *arg) if (my_thread_init()) { /* Can't use my_error since store_globals has not yet been called */ - thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES, - ER(ER_OUT_OF_RESOURCES)); + thd->stmt_da->set_error_status(thd, ER_OUT_OF_RESOURCES, + ER(ER_OUT_OF_RESOURCES), NULL); goto end; } #endif @@ -2316,8 +2318,8 @@ pthread_handler_t handle_delayed_insert(void *arg) if (init_thr_lock() || thd->store_globals()) { /* Can't use my_error since store_globals has perhaps failed */ - thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES, - ER(ER_OUT_OF_RESOURCES)); + thd->stmt_da->set_error_status(thd, ER_OUT_OF_RESOURCES, + ER(ER_OUT_OF_RESOURCES), NULL); thd->fatal_error(); goto err; } @@ -2744,7 +2746,7 @@ bool Delayed_insert::handle_inserts(void) { /* This should never happen */ table->file->print_error(error,MYF(0)); - sql_print_error("%s", thd.main_da.message()); + sql_print_error("%s", thd.stmt_da->message()); DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed in loop")); goto err; } @@ -2786,7 +2788,7 @@ bool Delayed_insert::handle_inserts(void) if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { // This shouldn't happen table->file->print_error(error,MYF(0)); - sql_print_error("%s", thd.main_da.message()); + sql_print_error("%s", thd.stmt_da->message()); DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed after loop")); goto err; } @@ -3254,10 +3256,12 @@ bool select_insert::send_eof() char buff[160]; if (info.ignore) sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, - (ulong) (info.records - info.copied), (ulong) thd->cuted_fields); + (ulong) (info.records - info.copied), + (ulong) thd->warning_info->statement_warn_count()); else sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, - (ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields); + (ulong) (info.deleted+info.updated), + (ulong) thd->warning_info->statement_warn_count()); thd->row_count_func= info.copied + info.deleted + ((thd->client_capabilities & CLIENT_FOUND_ROWS) ? info.touched : info.updated); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 76fd5354c51..47f66faf048 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -118,6 +118,7 @@ enum enum_sql_command { SQLCOM_SHOW_CREATE_TRIGGER, SQLCOM_ALTER_DB_UPGRADE, SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, + SQLCOM_SIGNAL, SQLCOM_RESIGNAL, /* When a command is added here, be sure it's also added in mysqld.cc @@ -1518,6 +1519,62 @@ public: CHARSET_INFO *m_underscore_cs; }; +/** + Abstract representation of a statement. + This class is an interface between the parser and the runtime. + The parser builds the appropriate sub classes of Sql_statement + to represent a SQL statement in the parsed tree. + The execute() method in the sub classes contain the runtime implementation. + Note that this interface is used for SQL statement recently implemented, + the code for older statements tend to load the LEX structure with more + attributes instead. + The recommended way to implement new statements is to sub-class + Sql_statement, as this improves code modularity (see the 'big switch' in + dispatch_command()), and decrease the total size of the LEX structure + (therefore saving memory in stored programs). +*/ +class Sql_statement : public Sql_alloc +{ +public: + /** + Execute this SQL statement. + @param thd the current thread. + @return 0 on success. + */ + virtual bool execute(THD *thd) = 0; + +protected: + /** + Constructor. + @param lex the LEX structure that represents parts of this statement. + */ + Sql_statement(struct st_lex *lex) + : m_lex(lex) + {} + + /** Destructor. */ + virtual ~Sql_statement() + { + /* + Sql_statement objects are allocated in thd->mem_root. + In MySQL, the C++ destructor is never called, the underlying MEM_ROOT is + simply destroyed instead. + Do not rely on the destructor for any cleanup. + */ + DBUG_ASSERT(FALSE); + } + +protected: + /** + The legacy LEX structure for this statement. + The LEX structure contains the existing properties of the parsed tree. + TODO: with time, attributes from LEX should move to sub classes of + Sql_statement, so that the parser only builds Sql_statement objects + with the minimum set of attributes, instead of a LEX structure that + contains the collection of every possible attribute. + */ + struct st_lex *m_lex; +}; /* The state of the lex parsing. This is saved in the THD struct */ @@ -1619,6 +1676,9 @@ typedef struct st_lex : public Query_tables_list */ nesting_map allow_sum_func; enum_sql_command sql_command; + + Sql_statement *m_stmt; + /* Usually `expr` rule of yacc is quite reused but some commands better not support subqueries which comes standard with this rule, like @@ -1894,6 +1954,36 @@ typedef struct st_lex : public Query_tables_list } LEX; +/** + Set_signal_information is a container used in the parsed tree to represent + the collection of assignments to condition items in the SIGNAL and RESIGNAL + statements. +*/ +class Set_signal_information +{ +public: + /** Constructor. */ + Set_signal_information(); + + /** Copy constructor. */ + Set_signal_information(const Set_signal_information& set); + + /** Destructor. */ + ~Set_signal_information() + {} + + /** Clear all items. */ + void clear(); + + /** + For each contition item assignment, m_item[] contains the parsed tree + that represents the expression assigned, if any. + m_item[] is an array indexed by Diag_condition_item_name. + */ + Item *m_item[LAST_DIAG_SET_PROPERTY+1]; +}; + + /** The internal state of the syntax parser. This object is only available during parsing, @@ -1920,6 +2010,12 @@ public: */ uchar *yacc_yyvs; + /** + Fragments of parsed tree, + used during the parsing of SIGNAL and RESIGNAL. + */ + Set_signal_information m_set_signal_info; + /* TODO: move more attributes from the LEX structure here. */ @@ -1976,6 +2072,6 @@ extern bool is_lex_native_function(const LEX_STRING *name); @} (End of group Semantic_Analysis) */ -int my_missing_function_error(const LEX_STRING &token, const char *name); +void my_missing_function_error(const LEX_STRING &token, const char *name); #endif /* MYSQL_SERVER */ diff --git a/sql/sql_load.cc b/sql/sql_load.cc index b7f33d51335..079b6f2fe43 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -514,7 +514,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, goto err; } sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted, - (ulong) (info.records - info.copied), (ulong) thd->cuted_fields); + (ulong) (info.records - info.copied), + (ulong) thd->warning_info->statement_warn_count()); if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; @@ -645,9 +646,10 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if (pos == read_info.row_end) { thd->cuted_fields++; /* Not enough fields */ - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_TOO_FEW_RECORDS, - ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_TOO_FEW_RECORDS, + ER(ER_WARN_TOO_FEW_RECORDS), + thd->warning_info->current_row_for_warning()); if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP) ((Field_timestamp*) field)->set_time(); } @@ -668,9 +670,10 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if (pos != read_info.row_end) { thd->cuted_fields++; /* To long row */ - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_TOO_MANY_RECORDS, - ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_TOO_MANY_RECORDS, + ER(ER_WARN_TOO_MANY_RECORDS), + thd->warning_info->current_row_for_warning()); } if (thd->killed || @@ -703,11 +706,12 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if (read_info.line_cuted) { thd->cuted_fields++; /* To long row */ - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_TOO_MANY_RECORDS, - ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_TOO_MANY_RECORDS, + ER(ER_WARN_TOO_MANY_RECORDS), + thd->warning_info->current_row_for_warning()); } - thd->row_count++; + thd->warning_info->inc_current_row_for_warning(); continue_loop:; } DBUG_RETURN(test(read_info.error)); @@ -773,7 +777,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name, - thd->row_count); + thd->warning_info->current_row_for_warning()); DBUG_RETURN(1); } field->set_null(); @@ -841,7 +845,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name, - thd->row_count); + thd->warning_info->current_row_for_warning()); DBUG_RETURN(1); } if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP) @@ -855,7 +859,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, thd->cuted_fields++; push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_TOO_FEW_RECORDS, - ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count); + ER(ER_WARN_TOO_FEW_RECORDS), + thd->warning_info->current_row_for_warning()); } else if (item->type() == Item::STRING_ITEM) { @@ -899,13 +904,13 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if (read_info.line_cuted) { thd->cuted_fields++; /* To long row */ - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), - thd->row_count); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), + thd->warning_info->current_row_for_warning()); if (thd->killed) DBUG_RETURN(1); } - thd->row_count++; + thd->warning_info->inc_current_row_for_warning(); continue_loop:; } DBUG_RETURN(test(read_info.error)); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a09fed98d65..59f947d925c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -305,8 +305,8 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_AUTHORS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CONTRIBUTORS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PRIVILEGES]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT; + sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT; sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS]= CF_STATUS_COMMAND; @@ -790,7 +790,7 @@ bool do_command(THD *thd) Consider moving to init_connect() instead. */ thd->clear_error(); // Clear error message - thd->main_da.reset_diagnostics_area(); + thd->stmt_da->reset_diagnostics_area(); net_new_transaction(net); @@ -1053,7 +1053,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, tbl_name= strmake(db.str, packet + 1, db_len)+1; strmake(tbl_name, packet + db_len + 2, tbl_len); if (mysql_table_dump(thd, &db, tbl_name) == 0) - thd->main_da.disable_status(); + thd->stmt_da->disable_status(); break; } case COM_CHANGE_USER: @@ -1348,7 +1348,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* We don't calculate statistics for this command */ general_log_print(thd, command, NullS); net->error=0; // Don't give 'abort' message - thd->main_da.disable_status(); // Don't send anything back + thd->stmt_da->disable_status(); // Don't send anything back error=TRUE; // End server break; @@ -1516,7 +1516,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #ifndef EMBEDDED_LIBRARY VOID(my_net_write(net, (uchar*) buff, length)); VOID(net_flush(net)); - thd->main_da.disable_status(); + thd->stmt_da->disable_status(); #endif break; } @@ -1582,7 +1582,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* report error issued during command execution */ if (thd->killed_errno()) { - if (! thd->main_da.is_set()) + if (! thd->stmt_da->is_set()) thd->send_kill_message(); } if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) @@ -1592,9 +1592,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } /* If commit fails, we should be able to reset the OK status. */ - thd->main_da.can_overwrite_status= TRUE; + thd->stmt_da->can_overwrite_status= TRUE; ha_autocommit_or_rollback(thd, thd->is_error()); - thd->main_da.can_overwrite_status= FALSE; + thd->stmt_da->can_overwrite_status= FALSE; thd->transaction.stmt.reset(); @@ -2035,8 +2035,14 @@ mysql_execute_command(THD *thd) variables, but for now this is probably good enough. Don't reset warnings when executing a stored routine. */ - if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont) - mysql_reset_errors(thd, 0); + if ((sql_command_flags[lex->sql_command] & CF_DIAGNOSTIC_STMT) != 0) + thd->warning_info->set_read_only(TRUE); + else + { + thd->warning_info->set_read_only(FALSE); + if (all_tables) + thd->warning_info->opt_clear_warning_info(thd->query_id); + } #ifdef HAVE_REPLICATION if (unlikely(thd->slave_thread)) @@ -4413,12 +4419,6 @@ create_sp_error: So just execute the statement. */ res= sp->execute_procedure(thd, &lex->value_list); - /* - If warnings have been cleared, we have to clear total_warn_count - too, otherwise the clients get confused. - */ - if (thd->warn_list.is_empty()) - thd->total_warn_count= 0; thd->variables.select_limit= select_limit; @@ -4449,7 +4449,7 @@ create_sp_error: else sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, &thd->sp_func_cache, FALSE); - mysql_reset_errors(thd, 0); + thd->warning_info->opt_clear_warning_info(thd->query_id); if (! sp) { if (lex->spname->m_db.str) @@ -4524,7 +4524,7 @@ create_sp_error: TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION); sp_result= sp_routine_exists_in_table(thd, type, lex->spname); - mysql_reset_errors(thd, 0); + thd->warning_info->opt_clear_warning_info(thd->query_id); if (sp_result == SP_OK) { char *db= lex->spname->m_db.str; @@ -4975,6 +4975,11 @@ create_sp_error: my_ok(thd, 1); break; } + case SQLCOM_SIGNAL: + case SQLCOM_RESIGNAL: + DBUG_ASSERT(lex->m_stmt != NULL); + res= lex->m_stmt->execute(thd); + break; default: #ifndef EMBEDDED_LIBRARY DBUG_ASSERT(0); /* Impossible */ @@ -5724,8 +5729,8 @@ void mysql_reset_thd_for_next_command(THD *thd) thd->user_var_events_alloc= thd->mem_root; } thd->clear_error(); - thd->main_da.reset_diagnostics_area(); - thd->total_warn_count=0; // Warnings for this query + thd->stmt_da->reset_diagnostics_area(); + thd->warning_info->reset_for_next_command(); thd->rand_used= 0; thd->sent_row_count= thd->examined_row_count= 0; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 350b5fdd38c..75a0c538e04 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -250,7 +250,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) int2store(buff+5, columns); int2store(buff+7, stmt->param_count); buff[9]= 0; // Guard against a 4.1 client - tmp= min(stmt->thd->total_warn_count, 65535); + tmp= min(stmt->thd->warning_info->statement_warn_count(), 65535); int2store(buff+10, tmp); /* @@ -265,7 +265,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) Protocol::SEND_EOF); } /* Flag that a response has already been sent */ - thd->main_da.disable_status(); + thd->stmt_da->disable_status(); DBUG_RETURN(error); } #else @@ -277,7 +277,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, thd->client_stmt_id= stmt->id; thd->client_param_count= stmt->param_count; thd->clear_error(); - thd->main_da.disable_status(); + thd->stmt_da->disable_status(); return 0; } @@ -1835,6 +1835,10 @@ static bool check_prepared_statement(Prepared_statement *stmt) lex->select_lex.context.resolve_in_table_list_only(select_lex-> get_table_list()); + /* Reset warning count for each query that uses tables */ + if (tables) + thd->warning_info->opt_clear_warning_info(thd->query_id); + switch (sql_command) { case SQLCOM_REPLACE: case SQLCOM_INSERT: @@ -2082,8 +2086,6 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) DBUG_VOID_RETURN; } - /* Reset warnings from previous command */ - mysql_reset_errors(thd, 0); sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); @@ -2656,7 +2658,7 @@ void mysqld_stmt_close(THD *thd, char *packet) Prepared_statement *stmt; DBUG_ENTER("mysqld_stmt_close"); - thd->main_da.disable_status(); + thd->stmt_da->disable_status(); if (!(stmt= find_prepared_statement(thd, stmt_id))) DBUG_VOID_RETURN; @@ -2731,7 +2733,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) status_var_increment(thd->status_var.com_stmt_send_long_data); - thd->main_da.disable_status(); + thd->stmt_da->disable_status(); #ifndef EMBEDDED_LIBRARY /* Minimal size of long data packet is 6 bytes */ if (packet_length < MYSQL_LONG_DATA_HEADER) @@ -2822,6 +2824,30 @@ Select_fetch_protocol_binary::send_data(List &fields) return rc; } +/******************************************************************* +* Reprepare_observer +*******************************************************************/ +/** Push an error to the error stack and return TRUE for now. */ + +bool +Reprepare_observer::report_error(THD *thd) +{ + /* + This 'error' is purely internal to the server: + - No exception handler is invoked, + - No condition is added in the condition area (warn_list). + The diagnostics area is set to an error status to enforce + that this thread execution stops and returns to the caller, + backtracking all the way to Prepared_statement::execute_loop(). + */ + thd->stmt_da->set_error_status(thd, ER_NEED_REPREPARE, + ER(ER_NEED_REPREPARE), "HY000"); + m_invalidated= TRUE; + + return TRUE; +} + + /*************************************************************************** Prepared_statement ****************************************************************************/ @@ -3262,7 +3288,7 @@ reexecute: reprepare_observer.is_invalidated() && reprepare_attempt++ < MAX_REPREPARE_ATTEMPTS) { - DBUG_ASSERT(thd->main_da.sql_errno() == ER_NEED_REPREPARE); + DBUG_ASSERT(thd->stmt_da->sql_errno() == ER_NEED_REPREPARE); thd->clear_error(); error= reprepare(); @@ -3325,12 +3351,12 @@ Prepared_statement::reprepare() #endif /* Clear possible warnings during reprepare, it has to be completely - transparent to the user. We use mysql_reset_errors() since + transparent to the user. We use clear_warning_info() since there were no separate query id issued for re-prepare. Sic: we can't simply silence warnings during reprepare, because if it's failed, we need to return all the warnings to the user. */ - mysql_reset_errors(thd, TRUE); + thd->warning_info->clear_warning_info(thd->query_id); } return error; } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 0ec8d91214c..b6ae8860cf5 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -796,7 +796,7 @@ err: @param mi Pointer to Master_info object for the slave's IO thread. - @param net_report If true, saves the exit status into thd->main_da. + @param net_report If true, saves the exit status into thd->stmt_da. @retval 0 success @retval 1 error @@ -934,7 +934,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) @param mi Pointer to Master_info object for the slave's IO thread. - @param net_report If true, saves the exit status into thd->main_da. + @param net_report If true, saves the exit status into thd->stmt_da. @retval 0 success @retval 1 error diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0adb38e0838..0a55a01fcc8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10861,7 +10861,6 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) so we don't touch it here. */ join->examined_rows++; - join->thd->row_count++; DBUG_ASSERT(join->examined_rows <= 1); } else if (join->send_row_on_empty_set()) @@ -11115,7 +11114,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) /* Set first_unmatched for the last inner table of this group */ join_tab->last_inner->first_unmatched= join_tab; } - join->thd->row_count= 0; + join->thd->warning_info->reset_current_row_for_warning(); error= (*join_tab->read_first_record)(join_tab); rc= evaluate_join_record(join, join_tab, error); @@ -11225,7 +11224,6 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, (See above join->return_tab= tab). */ join->examined_rows++; - join->thd->row_count++; DBUG_PRINT("counts", ("join->examined_rows++: %lu", (ulong) join->examined_rows)); @@ -11234,6 +11232,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, enum enum_nested_loop_state rc; /* A match from join_tab is found for the current partial join. */ rc= (*join_tab->next_select)(join, join_tab+1, 0); + join->thd->warning_info->inc_current_row_for_warning(); if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) return rc; if (join->return_tab < join_tab) @@ -11247,7 +11246,10 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_NO_MORE_ROWS; } else + { + join->thd->warning_info->inc_current_row_for_warning(); join_tab->read_record.file->unlock_row(); + } } else { @@ -11256,7 +11258,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, with the beginning coinciding with the current partial join. */ join->examined_rows++; - join->thd->row_count++; + join->thd->warning_info->inc_current_row_for_warning(); join_tab->read_record.file->unlock_row(); } return NESTED_LOOP_OK; diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index f8a8dea18ff..33058887952 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -242,7 +242,7 @@ bool servers_reload(THD *thd) if (simple_open_n_lock_tables(thd, tables)) { sql_print_error("Can't open and lock privilege tables: %s", - thd->main_da.message()); + thd->stmt_da->message()); goto end; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5c2c351652b..b16f050dea6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -598,7 +598,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if (open_normal_and_derived_tables(thd, table_list, 0)) { if (!table_list->view || - (thd->is_error() && thd->main_da.sql_errno() != ER_VIEW_INVALID)) + (thd->is_error() && thd->stmt_da->sql_errno() != ER_VIEW_INVALID)) DBUG_RETURN(TRUE); /* @@ -606,7 +606,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) issue a warning with 'warning' level status in case of invalid view and last error is ER_VIEW_INVALID */ - mysql_reset_errors(thd, true); + thd->warning_info->clear_warning_info(thd->query_id); thd->clear_error(); push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN, @@ -2986,7 +2986,7 @@ static int fill_schema_table_names(THD *thd, TABLE *table, default: DBUG_ASSERT(0); } - if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) + if (thd->is_error() && thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE) { thd->clear_error(); return 0; @@ -3350,10 +3350,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) can return an error without setting an error message in THD, which is a hack. This is why we have to check for res, then for thd->is_error() only then - for thd->main_da.sql_errno(). + for thd->stmt_da->sql_errno(). */ if (res && thd->is_error() && - thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) + thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE) { /* Hide error for not existing table. @@ -3507,7 +3507,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, /* there was errors during opening tables */ - const char *error= thd->is_error() ? thd->main_da.message() : ""; + const char *error= thd->is_error() ? thd->stmt_da->message() : ""; if (tables->view) table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); else if (tables->schema_table) @@ -3711,7 +3711,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, */ if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); res= 0; } @@ -4223,7 +4223,7 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, */ if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); res= 0; } @@ -4436,7 +4436,7 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, DBUG_RETURN(1); if (res && thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); } if (res) thd->clear_error(); @@ -4469,7 +4469,7 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4574,7 +4574,7 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4653,7 +4653,7 @@ static int get_schema_key_column_usage_record(THD *thd, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4848,7 +4848,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } @@ -5386,7 +5386,7 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, { if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + thd->stmt_da->sql_errno(), thd->stmt_da->message()); thd->clear_error(); DBUG_RETURN(0); } diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc new file mode 100644 index 00000000000..c9ab37272b8 --- /dev/null +++ b/sql/sql_signal.cc @@ -0,0 +1,510 @@ +/* Copyright (C) 2008 Sun Microsystems, Inc + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysql_priv.h" +#include "sp_head.h" +#include "sp_pcontext.h" +#include "sp_rcontext.h" +#include "sql_signal.h" + +/* + The parser accepts any error code (desired) + The runtime internally supports any error code (desired) + The client server protocol is limited to 16 bits error codes (restriction) + Enforcing the 65535 limit in the runtime until the protocol can change. +*/ +#define MAX_MYSQL_ERRNO UINT_MAX16 + +const LEX_STRING Diag_condition_item_names[]= +{ + { C_STRING_WITH_LEN("CLASS_ORIGIN") }, + { C_STRING_WITH_LEN("SUBCLASS_ORIGIN") }, + { C_STRING_WITH_LEN("CONSTRAINT_CATALOG") }, + { C_STRING_WITH_LEN("CONSTRAINT_SCHEMA") }, + { C_STRING_WITH_LEN("CONSTRAINT_NAME") }, + { C_STRING_WITH_LEN("CATALOG_NAME") }, + { C_STRING_WITH_LEN("SCHEMA_NAME") }, + { C_STRING_WITH_LEN("TABLE_NAME") }, + { C_STRING_WITH_LEN("COLUMN_NAME") }, + { C_STRING_WITH_LEN("CURSOR_NAME") }, + { C_STRING_WITH_LEN("MESSAGE_TEXT") }, + { C_STRING_WITH_LEN("MYSQL_ERRNO") }, + + { C_STRING_WITH_LEN("CONDITION_IDENTIFIER") }, + { C_STRING_WITH_LEN("CONDITION_NUMBER") }, + { C_STRING_WITH_LEN("CONNECTION_NAME") }, + { C_STRING_WITH_LEN("MESSAGE_LENGTH") }, + { C_STRING_WITH_LEN("MESSAGE_OCTET_LENGTH") }, + { C_STRING_WITH_LEN("PARAMETER_MODE") }, + { C_STRING_WITH_LEN("PARAMETER_NAME") }, + { C_STRING_WITH_LEN("PARAMETER_ORDINAL_POSITION") }, + { C_STRING_WITH_LEN("RETURNED_SQLSTATE") }, + { C_STRING_WITH_LEN("ROUTINE_CATALOG") }, + { C_STRING_WITH_LEN("ROUTINE_NAME") }, + { C_STRING_WITH_LEN("ROUTINE_SCHEMA") }, + { C_STRING_WITH_LEN("SERVER_NAME") }, + { C_STRING_WITH_LEN("SPECIFIC_NAME") }, + { C_STRING_WITH_LEN("TRIGGER_CATALOG") }, + { C_STRING_WITH_LEN("TRIGGER_NAME") }, + { C_STRING_WITH_LEN("TRIGGER_SCHEMA") } +}; + +const LEX_STRING Diag_statement_item_names[]= +{ + { C_STRING_WITH_LEN("NUMBER") }, + { C_STRING_WITH_LEN("MORE") }, + { C_STRING_WITH_LEN("COMMAND_FUNCTION") }, + { C_STRING_WITH_LEN("COMMAND_FUNCTION_CODE") }, + { C_STRING_WITH_LEN("DYNAMIC_FUNCTION") }, + { C_STRING_WITH_LEN("DYNAMIC_FUNCTION_CODE") }, + { C_STRING_WITH_LEN("ROW_COUNT") }, + { C_STRING_WITH_LEN("TRANSACTIONS_COMMITTED") }, + { C_STRING_WITH_LEN("TRANSACTIONS_ROLLED_BACK") }, + { C_STRING_WITH_LEN("TRANSACTION_ACTIVE") } +}; + +Set_signal_information::Set_signal_information() +{ + clear(); +} + +Set_signal_information::Set_signal_information( + const Set_signal_information& set) +{ + memcpy(m_item, set.m_item, sizeof(m_item)); +} + +void Set_signal_information::clear() +{ + memset(m_item, 0, sizeof(m_item)); +} + +void Signal_common::assign_defaults(MYSQL_ERROR *cond, + bool set_level_code, + MYSQL_ERROR::enum_warning_level level, + int sqlcode) +{ + if (set_level_code) + { + cond->m_level= level; + cond->m_sql_errno= sqlcode; + } + if (! cond->get_message_text()) + cond->set_builtin_message_text(ER(sqlcode)); +} + +void Signal_common::eval_defaults(THD *thd, MYSQL_ERROR *cond) +{ + DBUG_ASSERT(cond); + + const char* sqlstate; + bool set_defaults= (m_cond != 0); + + if (set_defaults) + { + /* + SIGNAL is restricted in sql_yacc.yy to only signal SQLSTATE conditions. + */ + DBUG_ASSERT(m_cond->type == sp_cond_type::state); + sqlstate= m_cond->sqlstate; + cond->set_sqlstate(sqlstate); + } + else + sqlstate= cond->get_sqlstate(); + + DBUG_ASSERT(sqlstate); + /* SQLSTATE class "00": illegal, rejected in the parser. */ + DBUG_ASSERT((sqlstate[0] != '0') || (sqlstate[1] != '0')); + + if ((sqlstate[0] == '0') && (sqlstate[1] == '1')) + { + /* SQLSTATE class "01": warning. */ + assign_defaults(cond, set_defaults, + MYSQL_ERROR::WARN_LEVEL_WARN, ER_SIGNAL_WARN); + } + else if ((sqlstate[0] == '0') && (sqlstate[1] == '2')) + { + /* SQLSTATE class "02": not found. */ + assign_defaults(cond, set_defaults, + MYSQL_ERROR::WARN_LEVEL_ERROR, ER_SIGNAL_NOT_FOUND); + } + else + { + /* other SQLSTATE classes : error. */ + assign_defaults(cond, set_defaults, + MYSQL_ERROR::WARN_LEVEL_ERROR, ER_SIGNAL_EXCEPTION); + } +} + +static bool assign_fixed_string(MEM_ROOT *mem_root, + CHARSET_INFO *dst_cs, + size_t max_char, + String *dst, + const String* src) +{ + bool truncated; + size_t numchars; + CHARSET_INFO *src_cs; + const char* src_str; + const char* src_end; + size_t src_len; + size_t to_copy; + char* dst_str; + size_t dst_len; + size_t dst_copied; + uint32 dummy_offset; + + src_str= src->ptr(); + if (src_str == NULL) + { + dst->set((const char*) NULL, 0, dst_cs); + return false; + } + + src_cs= src->charset(); + src_len= src->length(); + src_end= src_str + src_len; + numchars= src_cs->cset->numchars(src_cs, src_str, src_end); + + if (numchars <= max_char) + { + to_copy= src->length(); + truncated= false; + } + else + { + numchars= max_char; + to_copy= dst_cs->cset->charpos(dst_cs, src_str, src_end, numchars); + truncated= true; + } + + if (String::needs_conversion(to_copy, src_cs, dst_cs, & dummy_offset)) + { + dst_len= numchars * dst_cs->mbmaxlen; + dst_str= (char*) alloc_root(mem_root, dst_len + 1); + if (dst_str) + { + const char* well_formed_error_pos; + const char* cannot_convert_error_pos; + const char* from_end_pos; + + dst_copied= well_formed_copy_nchars(dst_cs, dst_str, dst_len, + src_cs, src_str, src_len, + numchars, + & well_formed_error_pos, + & cannot_convert_error_pos, + & from_end_pos); + DBUG_ASSERT(dst_copied <= dst_len); + dst_len= dst_copied; /* In case the copy truncated the data */ + dst_str[dst_copied]= '\0'; + } + } + else + { + dst_len= to_copy; + dst_str= (char*) alloc_root(mem_root, dst_len + 1); + if (dst_str) + { + memcpy(dst_str, src_str, to_copy); + dst_str[to_copy]= '\0'; + } + } + dst->set(dst_str, dst_len, dst_cs); + + return truncated; +} + +static int assign_condition_item(MEM_ROOT *mem_root, const char* name, THD *thd, + Item *set, String *ci) +{ + char str_buff[(64+1)*4]; /* Room for a null terminated UTF8 String 64 */ + String str_value(str_buff, sizeof(str_buff), & my_charset_utf8_bin); + String *str; + bool truncated; + + DBUG_ENTER("assign_condition_item"); + + if (set->is_null()) + { + thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR, name, "NULL"); + DBUG_RETURN(1); + } + + str= set->val_str(& str_value); + truncated= assign_fixed_string(mem_root, & my_charset_utf8_bin, 64, ci, str); + if (truncated) + { + if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES)) + { + thd->raise_error_printf(ER_COND_ITEM_TOO_LONG, name); + DBUG_RETURN(1); + } + + thd->raise_warning_printf(WARN_COND_ITEM_TRUNCATED, name); + } + + DBUG_RETURN(0); +} + + +int Signal_common::eval_signal_informations(THD *thd, MYSQL_ERROR *cond) +{ + struct cond_item_map + { + enum enum_diag_condition_item_name m_item; + String MYSQL_ERROR::*m_member; + }; + + static cond_item_map map[]= + { + { DIAG_CLASS_ORIGIN, & MYSQL_ERROR::m_class_origin }, + { DIAG_SUBCLASS_ORIGIN, & MYSQL_ERROR::m_subclass_origin }, + { DIAG_CONSTRAINT_CATALOG, & MYSQL_ERROR::m_constraint_catalog }, + { DIAG_CONSTRAINT_SCHEMA, & MYSQL_ERROR::m_constraint_schema }, + { DIAG_CONSTRAINT_NAME, & MYSQL_ERROR::m_constraint_name }, + { DIAG_CATALOG_NAME, & MYSQL_ERROR::m_catalog_name }, + { DIAG_SCHEMA_NAME, & MYSQL_ERROR::m_schema_name }, + { DIAG_TABLE_NAME, & MYSQL_ERROR::m_table_name }, + { DIAG_COLUMN_NAME, & MYSQL_ERROR::m_column_name }, + { DIAG_CURSOR_NAME, & MYSQL_ERROR::m_cursor_name } + }; + + Item *set; + String str_value; + String *str; + int i; + uint j; + int result= 1; + enum enum_diag_condition_item_name item_enum; + String *member; + const LEX_STRING *name; + + DBUG_ENTER("Signal_common::eval_signal_informations"); + + for (i= FIRST_DIAG_SET_PROPERTY; + i <= LAST_DIAG_SET_PROPERTY; + i++) + { + set= m_set_signal_information.m_item[i]; + if (set) + { + if (! set->fixed) + { + if (set->fix_fields(thd, & set)) + goto end; + m_set_signal_information.m_item[i]= set; + } + } + } + + /* + Generically assign all the UTF8 String 64 condition items + described in the map. + */ + for (j= 0; j < array_elements(map); j++) + { + item_enum= map[j].m_item; + set= m_set_signal_information.m_item[item_enum]; + if (set != NULL) + { + member= & (cond->* map[j].m_member); + name= & Diag_condition_item_names[item_enum]; + if (assign_condition_item(cond->m_mem_root, name->str, thd, set, member)) + goto end; + } + } + + /* + Assign the remaining attributes. + */ + + set= m_set_signal_information.m_item[DIAG_MESSAGE_TEXT]; + if (set != NULL) + { + if (set->is_null()) + { + thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR, + "MESSAGE_TEXT", "NULL"); + goto end; + } + /* + Enforce that SET MESSAGE_TEXT = evaluates the value + as VARCHAR(128) CHARACTER SET UTF8. + */ + bool truncated; + String utf8_text; + str= set->val_str(& str_value); + truncated= assign_fixed_string(thd->mem_root, & my_charset_utf8_bin, 128, + & utf8_text, str); + if (truncated) + { + if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES)) + { + thd->raise_error_printf(ER_COND_ITEM_TOO_LONG, + "MESSAGE_TEXT"); + goto end; + } + + thd->raise_warning_printf(WARN_COND_ITEM_TRUNCATED, + "MESSAGE_TEXT"); + } + + /* + See the comments + "Design notes about MYSQL_ERROR::m_message_text." + in file sql_error.cc + */ + String converted_text; + converted_text.set_charset(error_message_charset_info); + converted_text.append(utf8_text.ptr(), utf8_text.length(), + utf8_text.charset()); + cond->set_builtin_message_text(converted_text.c_ptr_safe()); + } + + set= m_set_signal_information.m_item[DIAG_MYSQL_ERRNO]; + if (set != NULL) + { + if (set->is_null()) + { + thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR, + "MYSQL_ERRNO", "NULL"); + goto end; + } + longlong code= set->val_int(); + if ((code <= 0) || (code > MAX_MYSQL_ERRNO)) + { + str= set->val_str(& str_value); + thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR, + "MYSQL_ERRNO", str->c_ptr_safe()); + goto end; + } + cond->m_sql_errno= (int) code; + } + + /* + The various item->val_xxx() methods don't return an error code, + but flag thd in case of failure. + */ + if (! thd->is_error()) + result= 0; + +end: + for (i= FIRST_DIAG_SET_PROPERTY; + i <= LAST_DIAG_SET_PROPERTY; + i++) + { + set= m_set_signal_information.m_item[i]; + if (set) + { + if (set->fixed) + set->cleanup(); + } + } + + DBUG_RETURN(result); +} + +bool Signal_common::raise_condition(THD *thd, MYSQL_ERROR *cond) +{ + bool result= TRUE; + + DBUG_ENTER("Signal_common::raise_condition"); + + DBUG_ASSERT(m_lex->query_tables == NULL); + + eval_defaults(thd, cond); + if (eval_signal_informations(thd, cond)) + DBUG_RETURN(result); + + /* SIGNAL should not signal WARN_LEVEL_NOTE */ + DBUG_ASSERT((cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) || + (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR)); + + MYSQL_ERROR *raised= NULL; + raised= thd->raise_condition(cond->get_sql_errno(), + cond->get_sqlstate(), + cond->get_level(), + cond->get_message_text()); + if (raised) + raised->copy_opt_attributes(cond); + + if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) + { + my_ok(thd); + result= FALSE; + } + + DBUG_RETURN(result); +} + +bool Signal_statement::execute(THD *thd) +{ + bool result= TRUE; + MYSQL_ERROR cond(thd->mem_root); + + DBUG_ENTER("Signal_statement::execute"); + + thd->stmt_da->reset_diagnostics_area(); + thd->row_count_func= 0; + thd->warning_info->clear_warning_info(thd->query_id); + + result= raise_condition(thd, &cond); + + DBUG_RETURN(result); +} + + +bool Resignal_statement::execute(THD *thd) +{ + MYSQL_ERROR *signaled; + int result= TRUE; + + DBUG_ENTER("Resignal_statement::execute"); + + thd->warning_info->m_warn_id= thd->query_id; + + if (! thd->spcont || ! (signaled= thd->spcont->raised_condition())) + { + thd->raise_error(ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER); + DBUG_RETURN(result); + } + + if (m_cond == NULL) + { + /* RESIGNAL without signal_value */ + result= raise_condition(thd, signaled); + DBUG_RETURN(result); + } + + /* RESIGNAL with signal_value */ + + /* Make room for 2 conditions */ + thd->warning_info->reserve_space(thd, 2); + + MYSQL_ERROR *raised= NULL; + raised= thd->raise_condition_no_handler(signaled->get_sql_errno(), + signaled->get_sqlstate(), + signaled->get_level(), + signaled->get_message_text()); + if (raised) + raised->copy_opt_attributes(signaled); + + result= raise_condition(thd, signaled); + + DBUG_RETURN(result); +} + diff --git a/sql/sql_signal.h b/sql/sql_signal.h new file mode 100644 index 00000000000..c9c1517f4ad --- /dev/null +++ b/sql/sql_signal.h @@ -0,0 +1,152 @@ +/* Copyright (C) 2008 Sun Microsystems, Inc + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef SQL_SIGNAL_H +#define SQL_SIGNAL_H + +/** + Signal_common represents the common properties of the SIGNAL and RESIGNAL + statements. +*/ +class Signal_common : public Sql_statement +{ +protected: + /** + Constructor. + @param lex the LEX structure for this statement. + @param cond the condition signaled if any, or NULL. + @param set collection of signal condition item assignments. + */ + Signal_common(LEX *lex, + const sp_cond_type_t *cond, + const Set_signal_information& set) + : Sql_statement(lex), + m_cond(cond), + m_set_signal_information(set) + {} + + virtual ~Signal_common() + {} + + /** + Assign the condition items 'MYSQL_ERRNO', 'level' and 'MESSAGE_TEXT' + default values of a condition. + @param cond the condition to update. + @param set_level_code true if 'level' and 'MYSQL_ERRNO' needs to be overwritten + @param level the level to assign + @param sqlcode the sql code to assign + */ + static void assign_defaults(MYSQL_ERROR *cond, + bool set_level_code, + MYSQL_ERROR::enum_warning_level level, + int sqlcode); + + /** + Evaluate the condition items 'SQLSTATE', 'MYSQL_ERRNO', 'level' and 'MESSAGE_TEXT' + default values for this statement. + @param thd the current thread. + @param cond the condition to update. + */ + void eval_defaults(THD *thd, MYSQL_ERROR *cond); + + /** + Evaluate each signal condition items for this statement. + @param thd the current thread. + @param cond the condition to update. + @return 0 on success. + */ + int eval_signal_informations(THD *thd, MYSQL_ERROR *cond); + + /** + Raise a SQL condition. + @param thd the current thread. + @param cond the condition to raise. + @return false on success. + */ + bool raise_condition(THD *thd, MYSQL_ERROR *cond); + + /** + The condition to signal or resignal. + This member is optional and can be NULL (RESIGNAL). + */ + const sp_cond_type_t *m_cond; + + /** + Collection of 'SET item = value' assignments in the + SIGNAL/RESIGNAL statement. + */ + Set_signal_information m_set_signal_information; +}; + +/** + Signal_statement represents a SIGNAL statement. +*/ +class Signal_statement : public Signal_common +{ +public: + /** + Constructor, used to represent a SIGNAL statement. + @param lex the LEX structure for this statement. + @param cond the SQL condition to signal (required). + @param set the collection of signal informations to signal. + */ + Signal_statement(LEX *lex, + const sp_cond_type_t *cond, + const Set_signal_information& set) + : Signal_common(lex, cond, set) + {} + + virtual ~Signal_statement() + {} + + /** + Execute a SIGNAL statement at runtime. + @param thd the current thread. + @return false on success. + */ + virtual bool execute(THD *thd); +}; + +/** + Resignal_statement represents a RESIGNAL statement. +*/ +class Resignal_statement : public Signal_common +{ +public: + /** + Constructor, used to represent a RESIGNAL statement. + @param lex the LEX structure for this statement. + @param cond the SQL condition to resignal (optional, may be NULL). + @param set the collection of signal informations to resignal. + */ + Resignal_statement(LEX *lex, + const sp_cond_type_t *cond, + const Set_signal_information& set) + : Signal_common(lex, cond, set) + {} + + virtual ~Resignal_statement() + {} + + /** + Execute a RESIGNAL statement at runtime. + @param thd the current thread. + @return 0 on success. + */ + virtual bool execute(THD *thd); +}; + +#endif + diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 81d00f46000..d0e4fb06b49 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4592,17 +4592,17 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (!table->table) { DBUG_PRINT("admin", ("open table failed")); - if (!thd->warn_list.elements) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + if (thd->warning_info->is_empty()) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE)); /* if it was a view will check md5 sum */ if (table->view && view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_VIEW_CHECKSUM, ER(ER_VIEW_CHECKSUM)); - if (thd->main_da.is_error() && - (thd->main_da.sql_errno() == ER_NO_SUCH_TABLE || - thd->main_da.sql_errno() == ER_FILE_NOT_FOUND)) + if (thd->stmt_da->is_error() && + (thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE || + thd->stmt_da->sql_errno() == ER_FILE_NOT_FOUND)) /* A missing table is just issued as a failed command */ result_code= HA_ADMIN_FAILED; else @@ -4644,7 +4644,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, table->table=0; // For query cache if (protocol->write()) goto err; - thd->main_da.reset_diagnostics_area(); + thd->stmt_da->reset_diagnostics_area(); continue; /* purecov: end */ } @@ -4704,8 +4704,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, we will store the error message in a result set row and then clear. */ - if (thd->main_da.is_ok()) - thd->main_da.reset_diagnostics_area(); + if (thd->stmt_da->is_ok()) + thd->stmt_da->reset_diagnostics_area(); goto send_result; } } @@ -4719,21 +4719,21 @@ send_result: lex->cleanup_after_one_table_open(); thd->clear_error(); // these errors shouldn't get client { - List_iterator_fast it(thd->warn_list); + List_iterator_fast it(thd->warning_info->warn_list()); MYSQL_ERROR *err; while ((err= it++)) { protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); protocol->store((char*) operator_name, system_charset_info); - protocol->store(warning_level_names[err->level].str, - warning_level_names[err->level].length, + protocol->store(warning_level_names[err->get_level()].str, + warning_level_names[err->get_level()].length, system_charset_info); - protocol->store(err->msg, system_charset_info); + protocol->store(err->get_message_text(), system_charset_info); if (protocol->write()) goto err; } - mysql_reset_errors(thd, true); + thd->warning_info->clear_warning_info(thd->query_id); } protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); @@ -4828,8 +4828,8 @@ send_result_message: we will store the error message in a result set row and then clear. */ - if (thd->main_da.is_ok()) - thd->main_da.reset_diagnostics_area(); + if (thd->stmt_da->is_ok()) + thd->stmt_da->reset_diagnostics_area(); ha_autocommit_or_rollback(thd, 0); close_thread_tables(thd); if (!result_code) // recreation went ok @@ -4847,7 +4847,7 @@ send_result_message: DBUG_ASSERT(thd->is_error()); if (thd->is_error()) { - const char *err_msg= thd->main_da.message(); + const char *err_msg= thd->stmt_da->message(); if (!thd->vio_ok()) { sql_print_error("%s", err_msg); @@ -7442,7 +7442,8 @@ err: the table to be altered isn't empty. Report error here. */ - if (alter_info->error_if_not_empty && thd->row_count) + if (alter_info->error_if_not_empty && + thd->warning_info->current_row_for_warning()) { const char *f_val= 0; enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE; @@ -7463,7 +7464,7 @@ err: } bool save_abort_on_warning= thd->abort_on_warning; thd->abort_on_warning= TRUE; - make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, f_val, strlength(f_val), t_type, alter_info->datetime_field->field_name); thd->abort_on_warning= save_abort_on_warning; @@ -7610,7 +7611,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE); if (ignore) to->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - thd->row_count= 0; + thd->warning_info->reset_current_row_for_warning(); restore_record(to, s->default_values); // Create empty record while (!(error=info.read_record(&info))) { @@ -7620,7 +7621,6 @@ copy_data_between_tables(TABLE *from,TABLE *to, error= 1; break; } - thd->row_count++; /* Return error if source table isn't empty. */ if (error_if_not_empty) { @@ -7670,6 +7670,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, } else found_count++; + thd->warning_info->inc_current_row_for_warning(); } end_read_record(&info); free_io_cache(from); diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc index 9fec0e3bc63..3549a44807e 100644 --- a/sql/sql_tablespace.cc +++ b/sql/sql_tablespace.cc @@ -31,7 +31,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info) { hton= ha_default_handlerton(thd); if (ts_info->storage_engine != 0) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_USING_OTHER_HANDLER, ER(ER_WARN_USING_OTHER_HANDLER), ha_resolve_storage_engine_name(hton), @@ -60,7 +60,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info) } else { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, ER(ER_ILLEGAL_HA_CREATE_OPTION), ha_resolve_storage_engine_name(hton), diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d4c1acabe11..f5c4b85e904 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -725,7 +725,7 @@ int mysql_update(THD *thd, } else table->file->unlock_row(); - thd->row_count++; + thd->warning_info->inc_current_row_for_warning(); if (thd->is_error()) { error= 1; @@ -831,8 +831,9 @@ int mysql_update(THD *thd, if (error < 0) { char buff[STRING_BUFFER_USUAL_SIZE]; - my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, - (ulong) thd->cuted_fields); + my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found, + (ulong) updated, + (ulong) thd->warning_info->statement_warn_count()); thd->row_count_func= (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; my_ok(thd, (ulong) thd->row_count_func, id, buff); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4ed9946a334..2d884cb739c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -43,6 +43,7 @@ #include "sp_pcontext.h" #include "sp_rcontext.h" #include "sp.h" +#include "sql_signal.h" #include "event_parse_data.h" #include #include @@ -507,6 +508,7 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, sp_head *sphead; struct p_elem_val *p_elem_value; enum index_hint_type index_hint; + Diag_condition_item_name diag_condition_item_name; } %{ @@ -588,6 +590,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CASCADED /* SQL-2003-R */ %token CASE_SYM /* SQL-2003-R */ %token CAST_SYM /* SQL-2003-R */ +%token CATALOG_NAME_SYM /* SQL-2003-N */ %token CHAIN_SYM /* SQL-2003-N */ %token CHANGE %token CHANGED @@ -596,6 +599,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CHECKSUM_SYM %token CHECK_SYM /* SQL-2003-R */ %token CIPHER_SYM +%token CLASS_ORIGIN_SYM /* SQL-2003-N */ %token CLIENT_SYM %token CLOSE_SYM /* SQL-2003-R */ %token COALESCE /* SQL-2003-N */ @@ -604,6 +608,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token COLLATION_SYM /* SQL-2003-N */ %token COLUMNS %token COLUMN_SYM /* SQL-2003-R */ +%token COLUMN_NAME_SYM /* SQL-2003-N */ %token COMMENT_SYM %token COMMITTED_SYM /* SQL-2003-N */ %token COMMIT_SYM /* SQL-2003-R */ @@ -611,10 +616,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token COMPLETION_SYM %token COMPRESSED_SYM %token CONCURRENT -%token CONDITION_SYM /* SQL-2003-N */ +%token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */ %token CONNECTION_SYM %token CONSISTENT_SYM %token CONSTRAINT /* SQL-2003-R */ +%token CONSTRAINT_CATALOG_SYM /* SQL-2003-N */ +%token CONSTRAINT_NAME_SYM /* SQL-2003-N */ +%token CONSTRAINT_SCHEMA_SYM /* SQL-2003-N */ %token CONTAINS_SYM /* SQL-2003-N */ %token CONTEXT_SYM %token CONTINUE_SYM /* SQL-2003-R */ @@ -628,6 +636,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CURDATE /* MYSQL-FUNC */ %token CURRENT_USER /* SQL-2003-R */ %token CURSOR_SYM /* SQL-2003-R */ +%token CURSOR_NAME_SYM /* SQL-2003-N */ %token CURTIME /* MYSQL-FUNC */ %token DATABASE %token DATABASES @@ -829,6 +838,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token MEDIUM_SYM %token MEMORY_SYM %token MERGE_SYM /* SQL-2003-R */ +%token MESSAGE_TEXT_SYM /* SQL-2003-N */ %token MICROSECOND_SYM /* MYSQL-FUNC */ %token MIGRATE_SYM %token MINUTE_MICROSECOND_SYM @@ -845,6 +855,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token MULTIPOINT %token MULTIPOLYGON %token MUTEX_SYM +%token MYSQL_ERRNO_SYM %token NAMES_SYM /* SQL-2003-N */ %token NAME_SYM /* SQL-2003-N */ %token NATIONAL_SYM /* SQL-2003-R */ @@ -945,6 +956,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token REPLICATION %token REQUIRE_SYM %token RESET_SYM +%token RESIGNAL_SYM /* SQL-2003-R */ %token RESOURCES %token RESTORE_SYM %token RESTRICT @@ -962,6 +974,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token RTREE_SYM %token SAVEPOINT_SYM /* SQL-2003-R */ %token SCHEDULE_SYM +%token SCHEMA_NAME_SYM /* SQL-2003-N */ %token SECOND_MICROSECOND_SYM %token SECOND_SYM /* SQL-2003-R */ %token SECURITY_SYM /* SQL-2003-N */ @@ -980,6 +993,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SHIFT_RIGHT /* OPERATOR */ %token SHOW %token SHUTDOWN +%token SIGNAL_SYM /* SQL-2003-R */ %token SIGNED_SYM %token SIMPLE_SYM /* SQL-2003-N */ %token SLAVE @@ -1013,6 +1027,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token STORAGE_SYM %token STRAIGHT_JOIN %token STRING_SYM +%token SUBCLASS_ORIGIN_SYM /* SQL-2003-N */ %token SUBDATE_SYM %token SUBJECT_SYM %token SUBPARTITIONS_SYM @@ -1029,6 +1044,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token TABLE_REF_PRIORITY %token TABLE_SYM /* SQL-2003-R */ %token TABLE_CHECKSUM_SYM +%token TABLE_NAME_SYM /* SQL-2003-N */ %token TEMPORARY /* SQL-2003-N */ %token TEMPTABLE_SYM %token TERMINATED @@ -1186,6 +1202,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); function_call_nonkeyword function_call_generic function_call_conflict + signal_allowed_expr %type NUM_literal @@ -1313,13 +1330,16 @@ END_OF_INPUT %type case_stmt_specification simple_case_stmt searched_case_stmt %type sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list -%type sp_cond sp_hcond +%type sp_cond sp_hcond sqlstate signal_value opt_signal_value %type sp_decls sp_decl %type sp_cursor_stmt %type sp_name %type index_hint_type %type index_hint_clause +%type signal_stmt resignal_stmt +%type signal_condition_information_item_name + %type '-' '+' '*' '/' '%' '(' ')' ',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_SYM BETWEEN_SYM CASE_SYM @@ -1440,12 +1460,14 @@ statement: | repair | replace | reset + | resignal_stmt | restore | revoke | rollback | savepoint | select | set + | signal_stmt | show | slave | start @@ -2339,12 +2361,12 @@ sp_decl: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_cond(&$2, TRUE)) - { - my_error(ER_SP_DUP_COND, MYF(0), $2.str); - MYSQL_YYABORT; - } - if(YYTHD->lex->spcont->push_cond(&$2, $5)) + if (spc->find_cond(&$2, TRUE)) + { + my_error(ER_SP_DUP_COND, MYF(0), $2.str); + MYSQL_YYABORT; + } + if(YYTHD->lex->spcont->push_cond(&$2, $5)) MYSQL_YYABORT; $$.vars= $$.hndlrs= $$.curs= 0; $$.conds= 1; @@ -2359,9 +2381,9 @@ sp_decl: sp_pcontext *ctx= lex->spcont; sp_instr_hpush_jump *i= new sp_instr_hpush_jump(sp->instructions(), ctx, $2, - ctx->current_var_count()); + ctx->current_var_count()); if (i == NULL || - sp->add_instr(i) || + sp->add_instr(i) || sp->push_backpatch(i, ctx->push_label((char *)"", 0))) MYSQL_YYABORT; } @@ -2378,15 +2400,15 @@ sp_decl: i= new sp_instr_hreturn(sp->instructions(), ctx, ctx->current_var_count()); if (i == NULL || - sp->add_instr(i)) + sp->add_instr(i)) MYSQL_YYABORT; } else { /* EXIT or UNDO handler, just jump to the end of the block */ i= new sp_instr_hreturn(sp->instructions(), ctx, 0); if (i == NULL || - sp->add_instr(i) || - sp->push_backpatch(i, lex->spcont->last_label())) /* Block end */ + sp->add_instr(i) || + sp->push_backpatch(i, lex->spcont->last_label())) /* Block end */ MYSQL_YYABORT; } lex->sphead->backpatch(hlab); @@ -2413,9 +2435,9 @@ sp_decl: } i= new sp_instr_cpush(sp->instructions(), ctx, $5, ctx->current_cursor_count()); - if (i == NULL || + if (i == NULL || sp->add_instr(i) || - ctx->push_cursor(&$2)) + ctx->push_cursor(&$2)) MYSQL_YYABORT; $$.vars= $$.conds= $$.hndlrs= 0; $$.curs= 1; @@ -2483,13 +2505,22 @@ sp_hcond_element: sp_cond: ulong_num { /* mysql errno */ + if ($1 == 0) + { + my_error(ER_WRONG_VALUE, MYF(0), "CONDITION", "0"); + MYSQL_YYABORT; + } $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t)); if ($$ == NULL) MYSQL_YYABORT; $$->type= sp_cond_type_t::number; $$->mysqlerr= $1; } - | SQLSTATE_SYM opt_value TEXT_STRING_literal + | sqlstate + ; + +sqlstate: + SQLSTATE_SYM opt_value TEXT_STRING_literal { /* SQLSTATE */ if (!sp_cond_check(&$3)) { @@ -2500,8 +2531,8 @@ sp_cond: if ($$ == NULL) MYSQL_YYABORT; $$->type= sp_cond_type_t::state; - memcpy($$->sqlstate, $3.str, 5); - $$->sqlstate[5]= '\0'; + memcpy($$->sqlstate, $3.str, SQLSTATE_LENGTH); + $$->sqlstate[SQLSTATE_LENGTH]= '\0'; } ; @@ -2547,6 +2578,160 @@ sp_hcond: } ; +signal_stmt: + SIGNAL_SYM signal_value opt_set_signal_information + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + Yacc_state *state= & thd->m_parser_state->m_yacc; + + lex->sql_command= SQLCOM_SIGNAL; + lex->m_stmt= new (thd->mem_root) Signal_statement(lex, $2, + state->m_set_signal_info); + if (lex->m_stmt == NULL) + MYSQL_YYABORT; + } + ; + +signal_value: + ident + { + LEX *lex= Lex; + sp_cond_type_t *cond; + if (lex->spcont == NULL) + { + /* SIGNAL foo cannot be used outside of stored programs */ + my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str); + MYSQL_YYABORT; + } + cond= lex->spcont->find_cond(&$1); + if (cond == NULL) + { + my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str); + MYSQL_YYABORT; + } + if (cond->type != sp_cond_type_t::state) + { + my_error(ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0)); + MYSQL_YYABORT; + } + $$= cond; + } + | sqlstate + { $$= $1; } + ; + +opt_signal_value: + /* empty */ + { $$= NULL; } + | signal_value + { $$= $1; } + ; + +opt_set_signal_information: + /* empty */ + { + YYTHD->m_parser_state->m_yacc.m_set_signal_info.clear(); + } + | SET signal_information_item_list + ; + +signal_information_item_list: + signal_condition_information_item_name EQ signal_allowed_expr + { + Set_signal_information *info; + info= & YYTHD->m_parser_state->m_yacc.m_set_signal_info; + int index= (int) $1; + info->clear(); + info->m_item[index]= $3; + } + | signal_information_item_list ',' + signal_condition_information_item_name EQ signal_allowed_expr + { + Set_signal_information *info; + info= & YYTHD->m_parser_state->m_yacc.m_set_signal_info; + int index= (int) $3; + if (info->m_item[index] != NULL) + { + my_error(ER_DUP_SIGNAL_SET, MYF(0), + Diag_condition_item_names[index].str); + MYSQL_YYABORT; + } + info->m_item[index]= $5; + } + ; + +/* + Only a limited subset of are allowed in SIGNAL/RESIGNAL. +*/ +signal_allowed_expr: + literal + { $$= $1; } + | variable + { + if ($1->type() == Item::FUNC_ITEM) + { + Item_func *item= (Item_func*) $1; + if (item->functype() == Item_func::SUSERVAR_FUNC) + { + /* + Don't allow the following syntax: + SIGNAL/RESIGNAL ... + SET = @foo := expr + */ + my_parse_error(ER(ER_SYNTAX_ERROR)); + MYSQL_YYABORT; + } + } + $$= $1; + } + | simple_ident + { $$= $1; } + ; + +/* conditions that can be set in signal / resignal */ +signal_condition_information_item_name: + CLASS_ORIGIN_SYM + { $$= DIAG_CLASS_ORIGIN; } + | SUBCLASS_ORIGIN_SYM + { $$= DIAG_SUBCLASS_ORIGIN; } + | CONSTRAINT_CATALOG_SYM + { $$= DIAG_CONSTRAINT_CATALOG; } + | CONSTRAINT_SCHEMA_SYM + { $$= DIAG_CONSTRAINT_SCHEMA; } + | CONSTRAINT_NAME_SYM + { $$= DIAG_CONSTRAINT_NAME; } + | CATALOG_NAME_SYM + { $$= DIAG_CATALOG_NAME; } + | SCHEMA_NAME_SYM + { $$= DIAG_SCHEMA_NAME; } + | TABLE_NAME_SYM + { $$= DIAG_TABLE_NAME; } + | COLUMN_NAME_SYM + { $$= DIAG_COLUMN_NAME; } + | CURSOR_NAME_SYM + { $$= DIAG_CURSOR_NAME; } + | MESSAGE_TEXT_SYM + { $$= DIAG_MESSAGE_TEXT; } + | MYSQL_ERRNO_SYM + { $$= DIAG_MYSQL_ERRNO; } + ; + +resignal_stmt: + RESIGNAL_SYM opt_signal_value opt_set_signal_information + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + Yacc_state *state= & thd->m_parser_state->m_yacc; + + lex->sql_command= SQLCOM_RESIGNAL; + lex->m_stmt= new (thd->mem_root) Resignal_statement(lex, $2, + state->m_set_signal_info); + if (lex->m_stmt == NULL) + MYSQL_YYABORT; + } + ; + sp_decl_idents: ident { @@ -2683,7 +2868,7 @@ sp_proc_stmt_return: i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3, sp->m_return_field_def.sql_type, lex); if (i == NULL || - sp->add_instr(i)) + sp->add_instr(i)) MYSQL_YYABORT; sp->m_flags|= sp_head::HAS_RETURN; } @@ -2923,7 +3108,7 @@ sp_if: sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx, $2, lex); if (i == NULL || - sp->push_backpatch(i, ctx->push_label((char *)"", 0)) || + sp->push_backpatch(i, ctx->push_label((char *)"", 0)) || sp->add_cont_backpatch(i) || sp->add_instr(i)) MYSQL_YYABORT; @@ -3205,7 +3390,7 @@ sp_unlabeled_control: if (i == NULL || lex->sphead->add_instr(i)) MYSQL_YYABORT; - } + } | WHILE_SYM { Lex->sphead->reset_lex(YYTHD); } expr DO_SYM @@ -3216,7 +3401,7 @@ sp_unlabeled_control: sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont, $3, lex); if (i == NULL || - /* Jumping forward */ + /* Jumping forward */ sp->push_backpatch(i, lex->spcont->last_label()) || sp->new_cont_backpatch(i) || sp->add_instr(i)) @@ -5023,6 +5208,7 @@ field_length: opt_field_length: /* empty */ { Lex->length=(char*) 0; /* use default length */ } | field_length { } + ; opt_precision: /* empty */ {} @@ -6410,7 +6596,7 @@ select_paren: sel->olap != UNSPECIFIED_OLAP_TYPE && sel->master_unit()->fake_select_lex) { - my_error(ER_WRONG_USAGE, MYF(0), + my_error(ER_WRONG_USAGE, MYF(0), "CUBE/ROLLUP", "ORDER BY"); MYSQL_YYABORT; } @@ -8705,24 +8891,25 @@ interval: ; interval_time_stamp: - interval_time_st {} - | FRAC_SECOND_SYM { - $$=INTERVAL_MICROSECOND; - /* - FRAC_SECOND was mistakenly implemented with - a wrong resolution. According to the ODBC - standard it should be nanoseconds, not - microseconds. Changing it to nanoseconds - in MySQL would mean making TIMESTAMPDIFF - and TIMESTAMPADD to return DECIMAL, since - the return value would be too big for BIGINT - Hence we just deprecate the incorrect - implementation without changing its - resolution. - */ - WARN_DEPRECATED(yythd, "6.2", "FRAC_SECOND", "MICROSECOND"); - } - ; + interval_time_st {} + | FRAC_SECOND_SYM + { + $$=INTERVAL_MICROSECOND; + /* + FRAC_SECOND was mistakenly implemented with + a wrong resolution. According to the ODBC + standard it should be nanoseconds, not + microseconds. Changing it to nanoseconds + in MySQL would mean making TIMESTAMPDIFF + and TIMESTAMPADD to return DECIMAL, since + the return value would be too big for BIGINT + Hence we just deprecate the incorrect + implementation without changing its + resolution. + */ + WARN_DEPRECATED(yythd, "6.2", "FRAC_SECOND", "MICROSECOND"); + } + ; interval_time_st: DAY_SYM { $$=INTERVAL_DAY; } @@ -11423,13 +11610,16 @@ keyword_sp: | BOOLEAN_SYM {} | BTREE_SYM {} | CASCADED {} + | CATALOG_NAME_SYM {} | CHAIN_SYM {} | CHANGED {} | CIPHER_SYM {} | CLIENT_SYM {} + | CLASS_ORIGIN_SYM {} | COALESCE {} | CODE_SYM {} | COLLATION_SYM {} + | COLUMN_NAME_SYM {} | COLUMNS {} | COMMITTED_SYM {} | COMPACT_SYM {} @@ -11438,10 +11628,14 @@ keyword_sp: | CONCURRENT {} | CONNECTION_SYM {} | CONSISTENT_SYM {} + | CONSTRAINT_CATALOG_SYM {} + | CONSTRAINT_SCHEMA_SYM {} + | CONSTRAINT_NAME_SYM {} | CONTEXT_SYM {} | CONTRIBUTORS_SYM {} | CPU_SYM {} | CUBE_SYM {} + | CURSOR_NAME_SYM {} | DATA_SYM {} | DATAFILE_SYM {} | DATETIME {} @@ -11533,6 +11727,7 @@ keyword_sp: | MEDIUM_SYM {} | MEMORY_SYM {} | MERGE_SYM {} + | MESSAGE_TEXT_SYM {} | MICROSECOND_SYM {} | MIGRATE_SYM {} | MINUTE_SYM {} @@ -11544,6 +11739,7 @@ keyword_sp: | MULTIPOINT {} | MULTIPOLYGON {} | MUTEX_SYM {} + | MYSQL_ERRNO_SYM {} | NAME_SYM {} | NAMES_SYM {} | NATIONAL_SYM {} @@ -11603,6 +11799,7 @@ keyword_sp: | ROW_SYM {} | RTREE_SYM {} | SCHEDULE_SYM {} + | SCHEMA_NAME_SYM {} | SECOND_SYM {} | SERIAL_SYM {} | SERIALIZABLE_SYM {} @@ -11621,6 +11818,7 @@ keyword_sp: | STATUS_SYM {} | STORAGE_SYM {} | STRING_SYM {} + | SUBCLASS_ORIGIN_SYM {} | SUBDATE_SYM {} | SUBJECT_SYM {} | SUBPARTITION_SYM {} @@ -11629,6 +11827,7 @@ keyword_sp: | SUSPEND_SYM {} | SWAPS_SYM {} | SWITCHES_SYM {} + | TABLE_NAME_SYM {} | TABLES {} | TABLE_CHECKSUM_SYM {} | TABLESPACE {} diff --git a/sql/table.cc b/sql/table.cc index 4442243ec14..d71a3ecd9bb 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1262,7 +1262,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, "Please do \"ALTER TABLE '%s' FORCE\" to fix it!", share->fieldnames.type_names[i], share->table_name.str, share->table_name.str); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_CRASHED_ON_USAGE, "Found incompatible DECIMAL field '%s' in %s; " "Please do \"ALTER TABLE '%s' FORCE\" to fix it!", @@ -1464,7 +1464,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, "Please do \"ALTER TABLE '%s' FORCE \" to fix it!", share->table_name.str, share->table_name.str); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_CRASHED_ON_USAGE, "Found wrong key definition in %s; " "Please do \"ALTER TABLE '%s' FORCE\" to fix " @@ -3351,20 +3351,20 @@ void TABLE_LIST::hide_view_error(THD *thd) /* Hide "Unknown column" or "Unknown function" error */ DBUG_ASSERT(thd->is_error()); - if (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR || - thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST || - thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION || - thd->main_da.sql_errno() == ER_PROCACCESS_DENIED_ERROR || - thd->main_da.sql_errno() == ER_COLUMNACCESS_DENIED_ERROR || - thd->main_da.sql_errno() == ER_TABLEACCESS_DENIED_ERROR || - thd->main_da.sql_errno() == ER_TABLE_NOT_LOCKED || - thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) + if (thd->stmt_da->sql_errno() == ER_BAD_FIELD_ERROR || + thd->stmt_da->sql_errno() == ER_SP_DOES_NOT_EXIST || + thd->stmt_da->sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION || + thd->stmt_da->sql_errno() == ER_PROCACCESS_DENIED_ERROR || + thd->stmt_da->sql_errno() == ER_COLUMNACCESS_DENIED_ERROR || + thd->stmt_da->sql_errno() == ER_TABLEACCESS_DENIED_ERROR || + thd->stmt_da->sql_errno() == ER_TABLE_NOT_LOCKED || + thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE) { TABLE_LIST *top= top_table(); thd->clear_error(); my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str); } - else if (thd->main_da.sql_errno() == ER_NO_DEFAULT_FOR_FIELD) + else if (thd->stmt_da->sql_errno() == ER_NO_DEFAULT_FOR_FIELD) { TABLE_LIST *top= top_table(); thd->clear_error(); @@ -3442,7 +3442,7 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure) TABLE_LIST *main_view= top_table(); if (ignore_failure) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED), main_view->view_db.str, main_view->view_name.str); return(VIEW_CHECK_SKIP); diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index 0764fe8be33..ed17f7968c0 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -44,9 +44,10 @@ extern "C" { returned in the error packet. - SHOW ERROR/SHOW WARNINGS may be empty. */ - thd->main_da.set_error_status(thd, - ER_OUT_OF_RESOURCES, - ER(ER_OUT_OF_RESOURCES)); + thd->stmt_da->set_error_status(thd, + ER_OUT_OF_RESOURCES, + ER(ER_OUT_OF_RESOURCES), + NULL); } } } diff --git a/sql/time.cc b/sql/time.cc index 962b65e454c..810d6426a01 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -748,7 +748,7 @@ void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level leve cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), type_str, str.c_ptr(), field_name, - (ulong) thd->row_count); + (ulong) thd->warning_info->current_row_for_warning()); else { if (time_type > MYSQL_TIMESTAMP_ERROR) diff --git a/sql/tztime.cc b/sql/tztime.cc index c7a4ad049ec..6757798ad32 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1645,7 +1645,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup)) { sql_print_warning("Can't open and lock time zone table: %s " - "trying to live without them", thd->main_da.message()); + "trying to live without them", thd->stmt_da->message()); /* We will try emulate that everything is ok */ return_val= time_zone_tables_exist= 0; goto end_with_setting_default_tz; diff --git a/sql/unireg.cc b/sql/unireg.cc index 68a352e4a44..028f774e057 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -55,10 +55,12 @@ static bool make_empty_rec(THD *thd, int file, enum legacy_db_type table_type, struct Pack_header_error_handler: public Internal_error_handler { - virtual bool handle_error(uint sql_errno, - const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd); + 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); bool is_handled; Pack_header_error_handler() :is_handled(FALSE) {} }; @@ -66,11 +68,14 @@ struct Pack_header_error_handler: public Internal_error_handler bool Pack_header_error_handler:: -handle_error(uint sql_errno, - const char * /* message */, - MYSQL_ERROR::enum_warning_level /* level */, - THD * /* thd */) +handle_condition(THD *, + uint sql_errno, + const char*, + MYSQL_ERROR::enum_warning_level, + const char*, + MYSQL_ERROR ** cond_hdl) { + *cond_hdl= NULL; is_handled= (sql_errno == ER_TOO_MANY_FIELDS); return is_handled; } diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 83a46ca9f9f..1e21f292727 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -153,7 +153,7 @@ extern "C" void myrg_print_wrong_table(const char *table_name) buf[db.length]= '.'; memcpy(buf + db.length + 1, name.str, name.length); buf[db.length + name.length + 1]= 0; - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ADMIN_WRONG_MRG_TABLE, ER(ER_ADMIN_WRONG_MRG_TABLE), buf); } From ea0d4516ed796179ef97a791bb04a646ac98610b Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Fri, 11 Sep 2009 01:15:41 -0600 Subject: [PATCH 004/274] Post merge fixes --- mysql-test/r/func_encrypt_nossl.result | 42 ++++----- .../suite/funcs_1/r/innodb_func_view.result | 92 +++++++++---------- .../funcs_1/r/innodb_storedproc_02.result | 3 - .../suite/funcs_1/r/memory_func_view.result | 92 +++++++++---------- .../funcs_1/r/memory_storedproc_02.result | 3 - .../suite/funcs_1/r/myisam_func_view.result | 92 +++++++++---------- .../funcs_1/r/myisam_storedproc_02.result | 3 - .../suite/funcs_1/r/ndb_func_view.result | 92 +++++++++---------- .../suite/funcs_1/r/ndb_storedproc_02.result | 3 - mysql-test/suite/funcs_1/r/storedproc.result | 73 +-------------- mysql-test/suite/ndb/r/ndb_multi_row.result | 6 +- 11 files changed, 210 insertions(+), 291 deletions(-) diff --git a/mysql-test/r/func_encrypt_nossl.result b/mysql-test/r/func_encrypt_nossl.result index d0df2335afa..fc003eec226 100644 --- a/mysql-test/r/func_encrypt_nossl.result +++ b/mysql-test/r/func_encrypt_nossl.result @@ -2,83 +2,83 @@ select des_encrypt("test", 'akeystr'); des_encrypt("test", 'akeystr') NULL Warnings: -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_encrypt("test", 1); des_encrypt("test", 1) NULL Warnings: -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_encrypt("test", 9); des_encrypt("test", 9) NULL Warnings: -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_encrypt("test", 100); des_encrypt("test", 100) NULL Warnings: -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_encrypt("test", NULL); des_encrypt("test", NULL) NULL Warnings: -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_encrypt(NULL, NULL); des_encrypt(NULL, NULL) NULL Warnings: -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_decrypt("test", 'anotherkeystr'); des_decrypt("test", 'anotherkeystr') NULL Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_decrypt(1, 1); des_decrypt(1, 1) NULL Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_decrypt(des_encrypt("test", 'thekey')); des_decrypt(des_encrypt("test", 'thekey')) NULL Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select hex(des_encrypt("hello")),des_decrypt(des_encrypt("hello")); hex(des_encrypt("hello")) des_decrypt(des_encrypt("hello")) NULL NULL Warnings: -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_decrypt(des_encrypt("hello",4)); des_decrypt(des_encrypt("hello",4)) NULL Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_decrypt(des_encrypt("hello",'test'),'test'); des_decrypt(des_encrypt("hello",'test'),'test') NULL Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("hello",'default_password')); hex(des_encrypt("hello")) hex(des_encrypt("hello",5)) hex(des_encrypt("hello",'default_password')) NULL NULL NULL Warnings: -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working -Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_decrypt(des_encrypt("hello"),'default_password'); des_decrypt(des_encrypt("hello"),'default_password') NULL Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_decrypt(des_encrypt("hello",4),'password4'); des_decrypt(des_encrypt("hello",4),'password4') NULL Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working SET @a=des_decrypt(des_encrypt("hello")); Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working flush des_key_file; select @a = des_decrypt(des_encrypt("hello")); @a = des_decrypt(des_encrypt("hello")) @@ -90,9 +90,9 @@ select hex(des_decrypt(des_encrypt("hello",4),'password2')); hex(des_decrypt(des_encrypt("hello",4),'password2')) NULL Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select hex(des_decrypt(des_encrypt("hello","hidden"))); hex(des_decrypt(des_encrypt("hello","hidden"))) NULL Warnings: -Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Warning 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working diff --git a/mysql-test/suite/funcs_1/r/innodb_func_view.result b/mysql-test/suite/funcs_1/r/innodb_func_view.result index 4beb0c8aaf2..172f410b949 100644 --- a/mysql-test/suite/funcs_1/r/innodb_func_view.result +++ b/mysql-test/suite/funcs_1/r/innodb_func_view.result @@ -945,8 +945,8 @@ AaBbCcDdEeFfGgHhIiJjÄäÜüÖö 9999999999999999999999999999999999.999999999999 0.000000000000000000000000000000 4 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select left('AaBbCcDdEeFfGgHhIiJjÄäÜüÖö',`t1_values`.`my_decimal`) AS `LEFT('AaBbCcDdEeFfGgHhIiJjÄäÜüÖö', my_decimal)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -960,8 +960,8 @@ AaBbCcDdEeFfGgHhIiJjÄäÜüÖö 9999999999999999999999999999999999.999999999999 0.000000000000000000000000000000 4 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -2587,9 +2587,9 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 0 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_decimal` as unsigned) AS `CAST(my_decimal AS UNSIGNED INTEGER)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -2603,9 +2603,9 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 0 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -2955,8 +2955,8 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 -1 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_decimal` as signed) AS `CAST(my_decimal AS SIGNED INTEGER)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -2970,8 +2970,8 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 -1 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -3282,10 +3282,10 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 30 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_double` as decimal(37,2)) AS `CAST(my_double AS DECIMAL(37,2))`,`t1_values`.`my_double` AS `my_double`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3300,10 +3300,10 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 30 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 DROP VIEW v1; @@ -3372,9 +3372,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 29 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_varbinary_1000` as decimal(37,2)) AS `CAST(my_varbinary_1000 AS DECIMAL(37,2))`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3389,9 +3389,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 29 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 DROP VIEW v1; @@ -3408,11 +3408,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 28 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' Warning 1292 Truncated incorrect DECIMAL value: '-1' Warning 1292 Truncated incorrect DECIMAL value: '-3333.3333' @@ -3430,11 +3430,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 28 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' Warning 1292 Truncated incorrect DECIMAL value: '-1' Warning 1292 Truncated incorrect DECIMAL value: '-3333.3333' @@ -3454,9 +3454,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 27 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_varchar_1000` as decimal(37,2)) AS `CAST(my_varchar_1000 AS DECIMAL(37,2))`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3471,9 +3471,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 27 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 DROP VIEW v1; @@ -3490,11 +3490,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 26 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection @@ -3510,11 +3510,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 26 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' DROP VIEW v1; diff --git a/mysql-test/suite/funcs_1/r/innodb_storedproc_02.result b/mysql-test/suite/funcs_1/r/innodb_storedproc_02.result index 65fc5b5afc9..3e2d084aa0c 100644 --- a/mysql-test/suite/funcs_1/r/innodb_storedproc_02.result +++ b/mysql-test/suite/funcs_1/r/innodb_storedproc_02.result @@ -550,9 +550,6 @@ exit handler 2 exit handler 2 exit handler 1 exit handler 1 -Warnings: -Note 1051 Unknown table 'tqq' -Note 1051 Unknown table 'tqq' create table res_t1(w char unique, x char); insert into res_t1 values ('a', 'b'); CREATE PROCEDURE h1 () diff --git a/mysql-test/suite/funcs_1/r/memory_func_view.result b/mysql-test/suite/funcs_1/r/memory_func_view.result index 4e48d9412d1..a386272b8ab 100644 --- a/mysql-test/suite/funcs_1/r/memory_func_view.result +++ b/mysql-test/suite/funcs_1/r/memory_func_view.result @@ -946,8 +946,8 @@ AaBbCcDdEeFfGgHhIiJjÄäÜüÖö 9999999999999999999999999999999999.999999999999 0.000000000000000000000000000000 4 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select left('AaBbCcDdEeFfGgHhIiJjÄäÜüÖö',`t1_values`.`my_decimal`) AS `LEFT('AaBbCcDdEeFfGgHhIiJjÄäÜüÖö', my_decimal)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -961,8 +961,8 @@ AaBbCcDdEeFfGgHhIiJjÄäÜüÖö 9999999999999999999999999999999999.999999999999 0.000000000000000000000000000000 4 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -2588,9 +2588,9 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 0 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_decimal` as unsigned) AS `CAST(my_decimal AS UNSIGNED INTEGER)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -2604,9 +2604,9 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 0 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -2956,8 +2956,8 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 -1 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_decimal` as signed) AS `CAST(my_decimal AS SIGNED INTEGER)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -2971,8 +2971,8 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 -1 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -3283,10 +3283,10 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 30 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_double` as decimal(37,2)) AS `CAST(my_double AS DECIMAL(37,2))`,`t1_values`.`my_double` AS `my_double`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3301,10 +3301,10 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 30 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 DROP VIEW v1; @@ -3373,9 +3373,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 29 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_varbinary_1000` as decimal(37,2)) AS `CAST(my_varbinary_1000 AS DECIMAL(37,2))`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3390,9 +3390,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 29 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 DROP VIEW v1; @@ -3409,11 +3409,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 28 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' Warning 1292 Truncated incorrect DECIMAL value: '-1' Warning 1292 Truncated incorrect DECIMAL value: '-3333.3333' @@ -3431,11 +3431,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 28 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' Warning 1292 Truncated incorrect DECIMAL value: '-1' Warning 1292 Truncated incorrect DECIMAL value: '-3333.3333' @@ -3455,9 +3455,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 27 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_varchar_1000` as decimal(37,2)) AS `CAST(my_varchar_1000 AS DECIMAL(37,2))`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3472,9 +3472,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 27 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 DROP VIEW v1; @@ -3491,11 +3491,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 26 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection @@ -3511,11 +3511,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 26 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' DROP VIEW v1; diff --git a/mysql-test/suite/funcs_1/r/memory_storedproc_02.result b/mysql-test/suite/funcs_1/r/memory_storedproc_02.result index 6b474621685..16dde71400e 100644 --- a/mysql-test/suite/funcs_1/r/memory_storedproc_02.result +++ b/mysql-test/suite/funcs_1/r/memory_storedproc_02.result @@ -551,9 +551,6 @@ exit handler 2 exit handler 2 exit handler 1 exit handler 1 -Warnings: -Note 1051 Unknown table 'tqq' -Note 1051 Unknown table 'tqq' create table res_t1(w char unique, x char); insert into res_t1 values ('a', 'b'); CREATE PROCEDURE h1 () diff --git a/mysql-test/suite/funcs_1/r/myisam_func_view.result b/mysql-test/suite/funcs_1/r/myisam_func_view.result index 4e48d9412d1..a386272b8ab 100644 --- a/mysql-test/suite/funcs_1/r/myisam_func_view.result +++ b/mysql-test/suite/funcs_1/r/myisam_func_view.result @@ -946,8 +946,8 @@ AaBbCcDdEeFfGgHhIiJjÄäÜüÖö 9999999999999999999999999999999999.999999999999 0.000000000000000000000000000000 4 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select left('AaBbCcDdEeFfGgHhIiJjÄäÜüÖö',`t1_values`.`my_decimal`) AS `LEFT('AaBbCcDdEeFfGgHhIiJjÄäÜüÖö', my_decimal)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -961,8 +961,8 @@ AaBbCcDdEeFfGgHhIiJjÄäÜüÖö 9999999999999999999999999999999999.999999999999 0.000000000000000000000000000000 4 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -2588,9 +2588,9 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 0 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_decimal` as unsigned) AS `CAST(my_decimal AS UNSIGNED INTEGER)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -2604,9 +2604,9 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 0 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -2956,8 +2956,8 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 -1 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_decimal` as signed) AS `CAST(my_decimal AS SIGNED INTEGER)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -2971,8 +2971,8 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 -1 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -3283,10 +3283,10 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 30 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_double` as decimal(37,2)) AS `CAST(my_double AS DECIMAL(37,2))`,`t1_values`.`my_double` AS `my_double`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3301,10 +3301,10 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 30 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 DROP VIEW v1; @@ -3373,9 +3373,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 29 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_varbinary_1000` as decimal(37,2)) AS `CAST(my_varbinary_1000 AS DECIMAL(37,2))`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3390,9 +3390,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 29 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 DROP VIEW v1; @@ -3409,11 +3409,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 28 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' Warning 1292 Truncated incorrect DECIMAL value: '-1' Warning 1292 Truncated incorrect DECIMAL value: '-3333.3333' @@ -3431,11 +3431,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 28 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' Warning 1292 Truncated incorrect DECIMAL value: '-1' Warning 1292 Truncated incorrect DECIMAL value: '-3333.3333' @@ -3455,9 +3455,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 27 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_varchar_1000` as decimal(37,2)) AS `CAST(my_varchar_1000 AS DECIMAL(37,2))`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3472,9 +3472,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 27 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 DROP VIEW v1; @@ -3491,11 +3491,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 26 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection @@ -3511,11 +3511,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 26 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' DROP VIEW v1; diff --git a/mysql-test/suite/funcs_1/r/myisam_storedproc_02.result b/mysql-test/suite/funcs_1/r/myisam_storedproc_02.result index 6b474621685..16dde71400e 100644 --- a/mysql-test/suite/funcs_1/r/myisam_storedproc_02.result +++ b/mysql-test/suite/funcs_1/r/myisam_storedproc_02.result @@ -551,9 +551,6 @@ exit handler 2 exit handler 2 exit handler 1 exit handler 1 -Warnings: -Note 1051 Unknown table 'tqq' -Note 1051 Unknown table 'tqq' create table res_t1(w char unique, x char); insert into res_t1 values ('a', 'b'); CREATE PROCEDURE h1 () diff --git a/mysql-test/suite/funcs_1/r/ndb_func_view.result b/mysql-test/suite/funcs_1/r/ndb_func_view.result index 4beb0c8aaf2..172f410b949 100644 --- a/mysql-test/suite/funcs_1/r/ndb_func_view.result +++ b/mysql-test/suite/funcs_1/r/ndb_func_view.result @@ -945,8 +945,8 @@ AaBbCcDdEeFfGgHhIiJjÄäÜüÖö 9999999999999999999999999999999999.999999999999 0.000000000000000000000000000000 4 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select left('AaBbCcDdEeFfGgHhIiJjÄäÜüÖö',`t1_values`.`my_decimal`) AS `LEFT('AaBbCcDdEeFfGgHhIiJjÄäÜüÖö', my_decimal)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -960,8 +960,8 @@ AaBbCcDdEeFfGgHhIiJjÄäÜüÖö 9999999999999999999999999999999999.999999999999 0.000000000000000000000000000000 4 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -2587,9 +2587,9 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 0 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_decimal` as unsigned) AS `CAST(my_decimal AS UNSIGNED INTEGER)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -2603,9 +2603,9 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 0 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -2955,8 +2955,8 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 -1 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_decimal` as signed) AS `CAST(my_decimal AS SIGNED INTEGER)`,`t1_values`.`my_decimal` AS `my_decimal`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -2970,8 +2970,8 @@ NULL NULL 1 0 0.000000000000000000000000000000 4 -1 -1.000000000000000000000000000000 5 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1292 Truncated incorrect DECIMAL value: '' DROP VIEW v1; @@ -3282,10 +3282,10 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 30 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_double` as decimal(37,2)) AS `CAST(my_double AS DECIMAL(37,2))`,`t1_values`.`my_double` AS `my_double`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3300,10 +3300,10 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 30 Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 -Error 1292 Truncated incorrect DECIMAL value: '' -Error 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 +Warning 1292 Truncated incorrect DECIMAL value: '' +Warning 1264 Out of range value for column 'CAST(my_double AS DECIMAL(37,2))' at row 1 DROP VIEW v1; @@ -3372,9 +3372,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 29 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_varbinary_1000` as decimal(37,2)) AS `CAST(my_varbinary_1000 AS DECIMAL(37,2))`,`t1_values`.`my_varbinary_1000` AS `my_varbinary_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3389,9 +3389,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 29 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 DROP VIEW v1; @@ -3408,11 +3408,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 28 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' Warning 1292 Truncated incorrect DECIMAL value: '-1' Warning 1292 Truncated incorrect DECIMAL value: '-3333.3333' @@ -3430,11 +3430,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 28 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' Warning 1292 Truncated incorrect DECIMAL value: '-1' Warning 1292 Truncated incorrect DECIMAL value: '-3333.3333' @@ -3454,9 +3454,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 27 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(`t1_values`.`my_varchar_1000` as decimal(37,2)) AS `CAST(my_varchar_1000 AS DECIMAL(37,2))`,`t1_values`.`my_varchar_1000` AS `my_varchar_1000`,`t1_values`.`id` AS `id` from `t1_values` latin1 latin1_swedish_ci @@ -3471,9 +3471,9 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 27 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 DROP VIEW v1; @@ -3490,11 +3490,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 26 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' SHOW CREATE VIEW v1; View Create View character_set_client collation_connection @@ -3510,11 +3510,11 @@ NULL NULL 1 -1.00 -1 5 -3333.33 -3333.3333 26 Warnings: -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: '<--------30 characters------->' -Error 1366 Incorrect decimal value: '' for column '' at row -1 +Warning 1366 Incorrect decimal value: '' for column '' at row -1 Warning 1292 Truncated incorrect DECIMAL value: ' ---äÖüß@µ*$-- ' DROP VIEW v1; diff --git a/mysql-test/suite/funcs_1/r/ndb_storedproc_02.result b/mysql-test/suite/funcs_1/r/ndb_storedproc_02.result index 65fc5b5afc9..3e2d084aa0c 100644 --- a/mysql-test/suite/funcs_1/r/ndb_storedproc_02.result +++ b/mysql-test/suite/funcs_1/r/ndb_storedproc_02.result @@ -550,9 +550,6 @@ exit handler 2 exit handler 2 exit handler 1 exit handler 1 -Warnings: -Note 1051 Unknown table 'tqq' -Note 1051 Unknown table 'tqq' create table res_t1(w char unique, x char); insert into res_t1 values ('a', 'b'); CREATE PROCEDURE h1 () diff --git a/mysql-test/suite/funcs_1/r/storedproc.result b/mysql-test/suite/funcs_1/r/storedproc.result index 3efb361dc82..ab917fce339 100644 --- a/mysql-test/suite/funcs_1/r/storedproc.result +++ b/mysql-test/suite/funcs_1/r/storedproc.result @@ -7128,8 +7128,6 @@ CALL sp1(); x y z 000 000 000 Warnings: -Warning 1264 Out of range value for column 'x' at row 1 -Warning 1264 Out of range value for column 'y' at row 1 Warning 1264 Out of range value for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7168,8 +7166,6 @@ CALL sp1(); x y z 00000 00000 00000 Warnings: -Warning 1264 Out of range value for column 'x' at row 1 -Warning 1264 Out of range value for column 'y' at row 1 Warning 1264 Out of range value for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7208,8 +7204,6 @@ CALL sp1(); x y z 00000000 00000000 00000000 Warnings: -Warning 1264 Out of range value for column 'x' at row 1 -Warning 1264 Out of range value for column 'y' at row 1 Warning 1264 Out of range value for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7248,8 +7242,6 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Warning 1264 Out of range value for column 'x' at row 1 -Warning 1264 Out of range value for column 'y' at row 1 Warning 1264 Out of range value for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7288,8 +7280,6 @@ CALL sp1(); x y z 00000000000000000000 00000000000000000000 00000000000000000000 Warnings: -Warning 1264 Out of range value for column 'x' at row 1 -Warning 1264 Out of range value for column 'y' at row 1 Warning 1264 Out of range value for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7310,8 +7300,6 @@ CALL sp1(); x y z -9999999999 -9999999999 -9999999999 Warnings: -Warning 1264 Out of range value for column 'x' at row 1 -Warning 1264 Out of range value for column 'y' at row 1 Warning 1264 Out of range value for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7323,8 +7311,6 @@ CALL sp1(); x y z 0 0 0 Warnings: -Note 1265 Data truncated for column 'x' at row 1 -Note 1265 Data truncated for column 'y' at row 1 Note 1265 Data truncated for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7336,8 +7322,6 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Warning 1264 Out of range value for column 'x' at row 1 -Warning 1264 Out of range value for column 'y' at row 1 Warning 1264 Out of range value for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7349,8 +7333,6 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Note 1265 Data truncated for column 'x' at row 1 -Note 1265 Data truncated for column 'y' at row 1 Note 1265 Data truncated for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7362,8 +7344,6 @@ CALL sp1(); x y z 0 0 0 Warnings: -Note 1265 Data truncated for column 'x' at row 1 -Note 1265 Data truncated for column 'y' at row 1 Note 1265 Data truncated for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7375,8 +7355,6 @@ CALL sp1(); x y z 0 0 0 Warnings: -Note 1265 Data truncated for column 'x' at row 1 -Note 1265 Data truncated for column 'y' at row 1 Note 1265 Data truncated for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7388,8 +7366,6 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Note 1265 Data truncated for column 'x' at row 1 -Note 1265 Data truncated for column 'y' at row 1 Note 1265 Data truncated for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -7401,8 +7377,6 @@ CALL sp1(); x y z 0000000000 0000000000 0000000000 Warnings: -Note 1265 Data truncated for column 'x' at row 1 -Note 1265 Data truncated for column 'y' at row 1 Note 1265 Data truncated for column 'z' at row 1 DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) @@ -13782,9 +13756,6 @@ END// CALL sp1(); x y @x NULL a 3 -Warnings: -Warning 1265 Data truncated for column 'y' at row 3 -Warning 1265 Data truncated for column 'y' at row 1 SELECT @v1, @v2; @v1 @v2 4 a @@ -15465,14 +15436,6 @@ count done 10 1 Warnings: Warning 1265 Data truncated for column 'name' at row 1 -Warning 1265 Data truncated for column 'name' at row 2 -Warning 1265 Data truncated for column 'name' at row 3 -Warning 1265 Data truncated for column 'name' at row 4 -Warning 1265 Data truncated for column 'name' at row 5 -Warning 1265 Data truncated for column 'name' at row 6 -Warning 1265 Data truncated for column 'name' at row 7 -Warning 1265 Data truncated for column 'name' at row 8 -Warning 1265 Data truncated for column 'name' at row 9 DROP PROCEDURE sp3; drop table res_t3_itisalongname_1381742_itsaverylongname_1381742; @@ -16387,7 +16350,6 @@ fn7(99999999999) 9999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn8; CREATE FUNCTION fn8( f1 decimal (0) unsigned zerofill) returns decimal (0) unsigned zerofill @@ -16432,7 +16394,6 @@ fn11(99999999999) 9999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn12; CREATE FUNCTION fn12( f1 decimal (0, 0) unsigned zerofill) returns decimal (0, 0) unsigned zerofill @@ -16533,7 +16494,6 @@ SELECT fn21_d_z(1.00e+00); fn21_d_z(1.00e+00) 0000000000000000000000000000000000000000000000000000000000000010 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn22; CREATE FUNCTION fn22( f1 decimal unsigned) returns decimal unsigned @@ -16545,7 +16505,6 @@ SELECT fn22(1.00e+00); fn22(1.00e+00) 10 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn23; CREATE FUNCTION fn23( f1 decimal unsigned zerofill) returns decimal unsigned zerofill @@ -16557,7 +16516,6 @@ SELECT fn23(1.00e+00); fn23(1.00e+00) 0000000010 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn24; CREATE FUNCTION fn24( f1 decimal zerofill) returns decimal zerofill @@ -16903,7 +16861,6 @@ fn56(-8388601) Warnings: Warning 1264 Out of range value for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 -Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn57; CREATE FUNCTION fn57( f1 numeric) returns numeric BEGIN @@ -16936,7 +16893,6 @@ SELECT fn59(9999999999); fn59(9999999999) 9999999999 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn60; CREATE FUNCTION fn60( f1 numeric (0) unsigned zerofill) returns numeric (0) unsigned zerofill @@ -16982,7 +16938,6 @@ SELECT fn63(9999999999); fn63(9999999999) 9999999999 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn64; CREATE FUNCTION fn64( f1 numeric (0, 0) unsigned zerofill) returns numeric (0, 0) unsigned zerofill @@ -17018,8 +16973,6 @@ fn66(-1e+36) -999999999999999999999999999999989.999999999999999999999999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 -Warning 1264 Out of range value for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn67; CREATE FUNCTION fn67( f1 numeric (63, 30) unsigned) returns numeric (63, 30) unsigned @@ -17032,7 +16985,6 @@ fn67(1e+36) 999999999999999999999999999999999.999999999999999999999999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn68; CREATE FUNCTION fn68( f1 numeric (63, 30) unsigned zerofill) returns numeric (63, 30) unsigned zerofill @@ -17045,7 +16997,6 @@ fn68(1e+36) 999999999999999999999999999999999.999999999999999999999999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn69; CREATE FUNCTION fn69( f1 numeric (63, 30) zerofill) returns numeric (63, 30) zerofill @@ -17213,7 +17164,6 @@ fn84(-32601) Warnings: Warning 1264 Out of range value for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 -Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn85; CREATE FUNCTION fn85( f1 tinyint) returns tinyint BEGIN @@ -17253,7 +17203,6 @@ fn88(-101) Warnings: Warning 1264 Out of range value for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 -Warning 1264 Out of range value for column 'f1' at row 1 DROP FUNCTION IF EXISTS fn89; CREATE FUNCTION fn89( f1 enum('1enum', '2enum')) returns enum('1enum', '2enum') BEGIN @@ -17511,7 +17460,6 @@ f1 9999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp8; CREATE PROCEDURE sp8( f1 decimal (0) unsigned zerofill) @@ -17556,7 +17504,6 @@ f1 9999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp12; CREATE PROCEDURE sp12( f1 decimal (0, 0) unsigned zerofill) @@ -17678,7 +17625,6 @@ CALL sp21(1.00e+00); f1 0000000000000000000000000000000000000000000000000000000000000010 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp22; CREATE PROCEDURE sp22( f1 decimal unsigned) @@ -17690,7 +17636,6 @@ CALL sp22(1.00e+00); f1 10 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp23; CREATE PROCEDURE sp23( f1 decimal unsigned zerofill) @@ -17702,7 +17647,6 @@ CALL sp23(1.00e+00); f1 0000000010 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp24; CREATE PROCEDURE sp24( f1 decimal zerofill) @@ -18048,7 +17992,6 @@ f1 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 -Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp57; CREATE PROCEDURE sp57( f1 numeric) BEGIN @@ -18081,7 +18024,6 @@ CALL sp59(9999999999); f1 9999999999 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp60; CREATE PROCEDURE sp60( f1 numeric (0) unsigned zerofill) @@ -18127,7 +18069,6 @@ CALL sp63(9999999999); f1 9999999999 Warnings: -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp64; CREATE PROCEDURE sp64( f1 numeric (0, 0) unsigned zerofill) @@ -18163,16 +18104,12 @@ f1 -999999999999999999999999999999989.999999999999999999999999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 -Warning 1264 Out of range value for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 CALL sp66_n( -1000000000000000000000000000000000000 ); f1 -999999999999999999999999999999989.999999999999999999999999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 -Warning 1264 Out of range value for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp67_nu; CREATE PROCEDURE sp67_nu( f1 numeric (63, 30) unsigned) @@ -18185,14 +18122,12 @@ f1 999999999999999999999999999999999.999999999999999999999999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 CALL sp67_nu( 1000000000000000000000000000000000000 ); f1 999999999999999999999999999999999.999999999999999999999999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp68_nuz; CREATE PROCEDURE sp68_nuz( f1 numeric (63, 30) unsigned zerofill) @@ -18205,14 +18140,12 @@ f1 999999999999999999999999999999999.999999999999999999999999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 CALL sp68_nuz( 1000000000000000000000000000000000000 ); f1 999999999999999999999999999999999.999999999999999999999999999999 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 -Note 1265 Data truncated for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp69_n_z; CREATE PROCEDURE sp69_n_z( f1 numeric (63, 30) zerofill) @@ -18395,7 +18328,6 @@ f1 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 -Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp85; CREATE PROCEDURE sp85( f1 tinyint) BEGIN @@ -18435,7 +18367,6 @@ f1 Warnings: Warning 1264 Out of range value for column 'f1' at row 1 Warning 1264 Out of range value for column 'f1' at row 1 -Warning 1264 Out of range value for column 'f1' at row 1 DROP PROCEDURE IF EXISTS sp89; CREATE PROCEDURE sp89( f1 enum('1enum', '2enum')) BEGIN @@ -22263,9 +22194,9 @@ END latin1 latin1_swedish_ci latin1_swedish_ci set @@sql_mode=''; CALL sp4(); Level Code Message -Error 1365 Division by 0 +Warning 1365 Division by 0 Warnings: -Error 1365 Division by 0 +Warning 1365 Division by 0 DROP PROCEDURE sp4; set @@sql_mode=''; diff --git a/mysql-test/suite/ndb/r/ndb_multi_row.result b/mysql-test/suite/ndb/r/ndb_multi_row.result index 3d34b16a1a8..96986490d23 100644 --- a/mysql-test/suite/ndb/r/ndb_multi_row.result +++ b/mysql-test/suite/ndb/r/ndb_multi_row.result @@ -63,6 +63,6 @@ t4 drop table t1, t2, t3, t4; drop table if exists t1, t3, t4; Warnings: -Error 155 Table 'test.t1' doesn't exist -Error 155 Table 'test.t3' doesn't exist -Error 155 Table 'test.t4' doesn't exist +Warning 155 Table 'test.t1' doesn't exist +Warning 155 Table 'test.t3' doesn't exist +Warning 155 Table 'test.t4' doesn't exist From 716099e07cd1a1726ad026281fdff3ef21b446f5 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 11 Sep 2009 22:26:35 +0200 Subject: [PATCH 005/274] This is the downport of Bug#24509 - 2048 file descriptor limit on windows needs increasing, also WL#3049 - improved Windows I/O The patch replaces the use of the POSIX I/O interfaces in mysys on Windows with the Win32 API calls (CreateFile, WriteFile, etc). The Windows HANDLE for the open file is stored in the my_file_info struct, along with a flag for append mode because the Windows API does not support opening files in append mode in all cases) The default max open files has been increased to 16384 and can be increased further by setting --max-open-files= during the server start. Another major change in this patch that almost all Windows specific file IO code has been moved to a new file my_winfile.c, greatly reducing the amount of code in #ifdef blocks within mysys, thus improving readability. Minor enhancements: - my_(f)stat() is changed to use __stati64 structure with 64 file size and timestamps. It will return correct file size now (C runtime implementation used to report outdated information) - my_lock on Windows is prepared to handle additional timeout parameter - after review : changed __WIN__ to _WIN32 in the new and changed code. client/mysqlbinlog.cc: fileno -> my_fileno client/readline.cc: fileno -> my_fileno include/config-win.h: Increase OS_FILE_LIMIT for Windows. Remove O_SHARE - Windows does not support it. Its definition conflicts with O_SHORT_LIVED, that has different semantics. include/my_dir.h: Use stat64 for stat() family of functions on Windows, because of 64 bit file size. include/my_global.h: Increased default value for open file limit to 16K include/my_sys.h: - my_file_info got new structure members - file handle and open flags - 2 new Windows-only mysys functions : my_get_osfhandle and my_osmaperr, modelled after Windows C runtime functions _get_osfhandle and _dosmaperr libmysql/CMakeLists.txt: new files my_winfile.c and my_winerr.c mysql-test/suite/large_tests/r/lock_tables_big.result: test for more then 2048 open file descriptors on Windows mysql-test/suite/large_tests/t/lock_tables_big.test: test for more then 2048 open file descriptors on Windows mysys/CMakeLists.txt: new files my_winfile.c and my_winerr.c mysys/Makefile.am: new files my_winfile.c and my_winerr.c mysys/default_modify.c: fileno -> my_fileno mysys/my_chsize.c: implementation of chsize on Windows now moved to my_winfile.c mysys/my_create.c: - my_sopen->my_win_open - close open file before removing (won't generally work on Windows otherwise) mysys/my_file.c: On Windows, files returned by my_open will not start with 0, but 2048 (making it simple to detect incompatible mix of CRT and mysys io functions) mysys/my_fopen.c: fileno->my_win_fileno , fclose->my_win_fclose, fdopen->my_win_fdopen Check for legal filename is done by my_win_[f]open functions mysys/my_fstream.c: fileno->my_fileno mysys/my_lib.c: Windows stat() functions are moved to my_winfile.c mysys/my_lock.c: Move Windows code under #ifdef to a separate function win_lock(). Add a parameter for lock wait timeout mysys/my_mmap.c: _get_osfhandle->my_get_osfhandle mysys/my_open.c: my_sopen->my_win_open (simpler interface) mysys/my_pread.c: moved most windows specific code to my_win_file.c Use my_win_pread mysys/my_quick.c: Use my_win_read/my_win_write mysys/my_read.c: Moved most of windows specific code to my_win_file.c Use my_win_read() mysys/my_seek.c: On Windows, use my_win_lseek() in my_seek()/my_tell() Removed dead code (synchronization of lseeks) Improved DBUG tracing (file position is ulonglong, not ulong) mysys/my_static.c: Removed array initialization. my_file_info_default is global variable thus it is initialized with all zeros anyway mysys/my_sync.c: _commit->my_win_fsync mysys/my_winerr.c: New file my_winerr.c Exports my_osmaperr modelled after undocumented C runtime function _dosmaperr(). The problem with _dosmaperr() used previously is that 1) it is nowhere documented and thus code relying on it is not guaranteed to work in subsequent releases on the C runtime 2) it is present only in static C runtime (mysqld does not link if compiled with /MD) mysys/my_winfile.c: New file my_winfile.c Implements ANSI/Posix file IO routines, when possible using native Windows IO, without C runtime (C runtime dropped because of the 2048 file descriptor limit). mysys/my_write.c: write->my_win_write mysys/mysys_priv.h: Declaration of Windows Posix functions (private to mysys, shall not be visible outside) storage/innobase/handler/ha_innodb.cc: mysys native Windows IO : correct innodb tmp file handling mysql_tmpfile does not return valid CRT file descriptor, thus it is not possible to dup() it. Instead, the native file handle has to be duplicated and then converted to CRT descriptor. storage/myisam/mi_locking.c: _commit->my_sync --- client/mysqlbinlog.cc | 2 +- client/mysqlslap.c | 2 +- client/readline.cc | 2 +- include/config-win.h | 3 +- include/my_dir.h | 4 + include/my_global.h | 41 +- include/my_sys.h | 24 +- libmysql/CMakeLists.txt | 2 +- .../large_tests/r/lock_tables_big.result | 1 + .../suite/large_tests/t/lock_tables_big.test | 32 + mysys/CMakeLists.txt | 2 +- mysys/Makefile.am | 2 +- mysys/default_modify.c | 6 +- mysys/my_chsize.c | 19 +- mysys/my_create.c | 15 +- mysys/my_dup.c | 6 +- mysys/my_file.c | 1 + mysys/my_fopen.c | 49 +- mysys/my_fstream.c | 17 +- mysys/my_lib.c | 26 +- mysys/my_lock.c | 140 +++- mysys/my_mmap.c | 6 +- mysys/my_open.c | 223 +----- mysys/my_pread.c | 103 +-- mysys/my_quick.c | 22 +- mysys/my_read.c | 21 +- mysys/my_seek.c | 38 +- mysys/my_static.c | 2 +- mysys/my_sync.c | 4 +- mysys/my_winerr.c | 123 ++++ mysys/my_winfile.c | 671 ++++++++++++++++++ mysys/my_write.c | 39 +- mysys/mysys_priv.h | 24 + storage/innobase/handler/ha_innodb.cc | 22 + storage/myisam/mi_locking.c | 8 +- 35 files changed, 1284 insertions(+), 418 deletions(-) create mode 100644 mysql-test/suite/large_tests/r/lock_tables_big.result create mode 100644 mysql-test/suite/large_tests/t/lock_tables_big.test create mode 100644 mysys/my_winerr.c create mode 100644 mysys/my_winfile.c diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 82af7ca65f6..a01918caad4 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1909,7 +1909,7 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, return ERROR_STOP; } #endif - if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0, + if (init_io_cache(file, my_fileno(stdin), 0, READ_CACHE, (my_off_t) 0, 0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE))) { error("Failed to init IO cache."); diff --git a/client/mysqlslap.c b/client/mysqlslap.c index 70abfbb7136..6a016b72383 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -1199,7 +1199,7 @@ get_options(int *argc,char ***argv) if (opt_csv_str[0] == '-') { - csv_file= fileno(stdout); + csv_file= my_fileno(stdout); } else { diff --git a/client/readline.cc b/client/readline.cc index b32cb71b0de..73ce7c3b8c7 100644 --- a/client/readline.cc +++ b/client/readline.cc @@ -33,7 +33,7 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file) if (!(line_buff=(LINE_BUFFER*) my_malloc(sizeof(*line_buff),MYF(MY_WME | MY_ZEROFILL)))) return 0; - if (init_line_buffer(line_buff,fileno(file),IO_SIZE,max_size)) + if (init_line_buffer(line_buff,my_fileno(file),IO_SIZE,max_size)) { my_free(line_buff,MYF(0)); return 0; diff --git a/include/config-win.h b/include/config-win.h index af4915440b1..bcad4e04346 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -65,7 +65,6 @@ #endif /* File and lock constants */ -#define O_SHARE 0x1000 /* Open file in sharing mode */ #ifdef __BORLANDC__ #define F_RDLCK LK_NBLCK /* read lock */ #define F_WRLCK LK_NBRLCK /* write lock */ @@ -336,7 +335,7 @@ inline ulonglong double2ulonglong(double d) #define FN_DEVCHAR ':' #define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */ #define FN_NO_CASE_SENCE /* Files are not case-sensitive */ -#define OS_FILE_LIMIT 2048 +#define OS_FILE_LIMIT UINT_MAX /* No limit*/ #define DO_NOT_REMOVE_THREAD_WRAPPERS #define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V)) diff --git a/include/my_dir.h b/include/my_dir.h index 06509a3af19..90d708ac811 100644 --- a/include/my_dir.h +++ b/include/my_dir.h @@ -69,7 +69,11 @@ typedef struct my_stat #else +#if(_MSC_VER) +#define MY_STAT struct _stati64 /* 64 bit file size */ +#else #define MY_STAT struct stat /* Orginal struct have what we need */ +#endif #endif /* USE_MY_STAT_STRUCT */ diff --git a/include/my_global.h b/include/my_global.h index 4ad851e9e5d..f7e65d80dbb 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -736,7 +736,41 @@ typedef SOCKET_SIZE_TYPE size_socket; #define FN_LIBCHAR '/' #define FN_ROOTDIR "/" #endif -#define MY_NFILE 64 /* This is only used to save filenames */ + +/* + MY_FILE_MIN is Windows speciality and is used to quickly detect + the mismatch of CRT and mysys file IO usage on Windows at runtime. + CRT file descriptors can be in the range 0-2047, whereas descriptors returned + by my_open() will start with 2048. If a file descriptor with value less then + MY_FILE_MIN is passed to mysys IO function, chances are it stemms from + open()/fileno() and not my_open()/my_fileno. + + For Posix, mysys functions are light wrappers around libc, and MY_FILE_MIN + is logically 0. +*/ + +#ifdef _WIN32 +#define MY_FILE_MIN 2048 +#else +#define MY_FILE_MIN 0 +#endif + +/* + MY_NFILE is the default size of my_file_info array. + + It is larger on Windows, because it all file handles are stored in my_file_info + Default size is 16384 and this should be enough for most cases.If it is not + enough, --max-open-files with larger value can be used. + + For Posix , my_file_info array is only used to store filenames for + error reporting and its size is not a limitation for number of open files. +*/ +#ifdef _WIN32 +#define MY_NFILE (16384 + MY_FILE_MIN) +#else +#define MY_NFILE 64 +#endif + #ifndef OS_FILE_LIMIT #define OS_FILE_LIMIT 65535 #endif @@ -773,9 +807,8 @@ typedef SOCKET_SIZE_TYPE size_socket; /* Some things that this system doesn't have */ #define NO_HASH /* Not needed anymore */ -#ifdef __WIN__ -#define NO_DIR_LIBRARY /* Not standar dir-library */ -#define USE_MY_STAT_STRUCT /* For my_lib */ +#ifdef _WIN32 +#define NO_DIR_LIBRARY /* Not standard dir-library */ #endif /* Some defines of functions for portability */ diff --git a/include/my_sys.h b/include/my_sys.h index 222564e0b44..849c35606b1 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -310,9 +310,13 @@ enum file_type struct st_my_file_info { - char * name; - enum file_type type; -#if defined(THREAD) && !defined(HAVE_PREAD) + char *name; +#ifdef _WIN32 + HANDLE fhandle; /* win32 file handle */ + int oflag; /* open flags, e.g O_APPEND */ +#endif + enum file_type type; +#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32) pthread_mutex_t mutex; #endif }; @@ -617,12 +621,12 @@ extern void *my_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); -#ifdef __WIN__ -extern int my_access(const char *path, int amode); -extern File my_sopen(const char *path, int oflag, int shflag, int pmode); +#ifdef _WIN32 +extern int my_access(const char *path, int amode); #else #define my_access access #endif + extern int check_if_legal_filename(const char *path); extern int check_if_legal_tablename(const char *path); @@ -633,6 +637,13 @@ extern int nt_share_delete(const char *name,myf MyFlags); #define my_delete_allow_opened(fname,flags) my_delete((fname),(flags)) #endif +#ifdef _WIN32 +/* Windows-only functions (CRT equivalents)*/ +extern File my_sopen(const char *path, int oflag, int shflag, int pmode); +extern HANDLE my_get_osfhandle(File fd); +extern void my_osmaperr(unsigned long last_error); +#endif + #ifndef TERMINATE extern void TERMINATE(FILE *file, uint flag); #endif @@ -641,6 +652,7 @@ extern void wait_for_free_space(const char *filename, int errors); extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags); extern int my_fclose(FILE *fd,myf MyFlags); +extern File my_fileno(FILE *fd); extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); extern int my_sync(File fd, myf my_flags); extern int my_sync_dir(const char *dir_name, myf my_flags); diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index 55138e4aa06..b252d94b50e 100755 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -98,7 +98,7 @@ SET(CLIENT_SOURCES ../mysys/array.c ../strings/bchange.c ../strings/bmove.c ../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c ../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c ../mysys/mf_qsort.c - ../mysys/my_getsystime.c ../mysys/my_sync.c ${LIB_SOURCES}) + ../mysys/my_getsystime.c ../mysys/my_sync.c ../mysys/my_winerr.c ../mysys/my_winfile.c ${LIB_SOURCES}) # Need to set USE_TLS for building the DLL, since __declspec(thread) # approach to thread local storage does not work properly in DLLs. diff --git a/mysql-test/suite/large_tests/r/lock_tables_big.result b/mysql-test/suite/large_tests/r/lock_tables_big.result new file mode 100644 index 00000000000..de639143055 --- /dev/null +++ b/mysql-test/suite/large_tests/r/lock_tables_big.result @@ -0,0 +1 @@ +all done diff --git a/mysql-test/suite/large_tests/t/lock_tables_big.test b/mysql-test/suite/large_tests/t/lock_tables_big.test new file mode 100644 index 00000000000..41dcff3577c --- /dev/null +++ b/mysql-test/suite/large_tests/t/lock_tables_big.test @@ -0,0 +1,32 @@ +# +# Bug#24509 cannot use more than 2048 file descriptors on windows +# +--disable_query_log +create database many_tables; +use many_tables; +let $max_tables=3000; +let $i=$max_tables; + +--disable_warnings +create table t (i int); +let $table_list=t READ; + +while ($i) +{ + eval create table t$i (i int); + let $table_list= $table_list ,t$i READ; + dec $i; +} + +#lock all tables we just created (resembles mysqldump startup is doing with --all-databases operation) +#There will be 3 descriptors for each table (table.FRM, table.MYI and table.MYD files) means 9000 files +#descriptors altogether. For Microsoft C runtime, this is way too many. + +eval LOCK TABLES $table_list; +unlock tables; + +drop database many_tables; +--disable_query_log +--echo all done + + diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 545278485d1..f2d540d2295 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -39,7 +39,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_ my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c - my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c + my_winerr.c my_winfile.c my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c rijndael.c safemalloc.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c) diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 4b07cf89676..fdc93ba1a4a 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -56,7 +56,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ thr_mutex.c thr_rwlock.c \ CMakeLists.txt mf_soundex.c \ - my_conio.c my_wincond.c my_winthread.c + my_conio.c my_wincond.c my_winthread.c my_winerr.c my_winfile.c libmysys_a_LIBADD = @THREAD_LOBJECTS@ # test_dir_DEPENDENCIES= $(LIBRARIES) # testhash_DEPENDENCIES= $(LIBRARIES) diff --git a/mysys/default_modify.c b/mysys/default_modify.c index 88df0122da2..b214a1df445 100644 --- a/mysys/default_modify.c +++ b/mysys/default_modify.c @@ -21,7 +21,7 @@ #define BUFF_SIZE 1024 #define RESERVE 1024 /* Extend buffer with this extent */ -#ifdef __WIN__ +#ifdef _WIN32 #define NEWLINE "\r\n" #define NEWLINE_LEN 2 #else @@ -78,7 +78,7 @@ int modify_defaults_file(const char *file_location, const char *option, DBUG_RETURN(2); /* my_fstat doesn't use the flag parameter */ - if (my_fstat(fileno(cnf_file), &file_stat, MYF(0))) + if (my_fstat(my_fileno(cnf_file), &file_stat, MYF(0))) goto malloc_err; if (option && option_value) @@ -213,7 +213,7 @@ int modify_defaults_file(const char *file_location, const char *option, if (opt_applied) { /* Don't write the file if there are no changes to be made */ - if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0, + if (my_chsize(my_fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0, MYF(MY_WME)) || my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) || my_fwrite(cnf_file, (uchar*) file_buffer, (size_t) (dst_ptr - file_buffer), diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c index b1dbb22c687..b9013811b34 100644 --- a/mysys/my_chsize.c +++ b/mysys/my_chsize.c @@ -52,20 +52,13 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags) if (oldsize > newlength) { -#if defined(HAVE_SETFILEPOINTER) - /* This is for the moment only true on windows */ - long is_success; - HANDLE win_file= (HANDLE) _get_osfhandle(fd); - long length_low, length_high; - length_low= (long) (ulong) newlength; - length_high= (long) ((ulonglong) newlength >> 32); - is_success= SetFilePointer(win_file, length_low, &length_high, FILE_BEGIN); - if (is_success == -1 && (my_errno= GetLastError()) != NO_ERROR) +#ifdef _WIN32 + if (my_win_chsize(fd, newlength)) + { + my_errno= errno; goto err; - if (SetEndOfFile(win_file)) - DBUG_RETURN(0); - my_errno= GetLastError(); - goto err; + } + DBUG_RETURN(0); #elif defined(HAVE_FTRUNCATE) if (ftruncate(fd, (off_t) newlength)) { diff --git a/mysys/my_create.c b/mysys/my_create.c index 5c9a1e027d2..d0436276d03 100644 --- a/mysys/my_create.c +++ b/mysys/my_create.c @@ -18,7 +18,7 @@ #include "mysys_err.h" #include #include -#if defined(__WIN__) +#if defined(_WIN32) #include #endif @@ -41,16 +41,12 @@ File my_create(const char *FileName, int CreateFlags, int access_flags, FileName, CreateFlags, access_flags, MyFlags)); #if !defined(NO_OPEN_3) - fd = open((char *) FileName, access_flags | O_CREAT, + fd= open((char *) FileName, access_flags | O_CREAT, CreateFlags ? CreateFlags : my_umask); -#elif defined(VMS) - fd = open((char *) FileName, access_flags | O_CREAT, 0, - "ctx=stm","ctx=bin"); -#elif defined(__WIN__) - fd= my_sopen((char *) FileName, access_flags | O_CREAT | O_BINARY, - SH_DENYNO, MY_S_IREAD | MY_S_IWRITE); +#elif defined(_WIN32) + fd= my_win_open(FileName, access_flags | O_CREAT); #else - fd = open(FileName, access_flags); + fd= open(FileName, access_flags); #endif if ((MyFlags & MY_SYNC_DIR) && (fd >=0) && @@ -71,6 +67,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags, if (unlikely(fd >= 0 && rc < 0)) { int tmp= my_errno; + my_close(fd, MyFlags); my_delete(FileName, MyFlags); my_errno= tmp; } diff --git a/mysys/my_dup.c b/mysys/my_dup.c index 55f5e0c0099..5fdd6e9f364 100644 --- a/mysys/my_dup.c +++ b/mysys/my_dup.c @@ -29,7 +29,11 @@ File my_dup(File file, myf MyFlags) const char *filename; DBUG_ENTER("my_dup"); DBUG_PRINT("my",("file: %d MyFlags: %d", file, MyFlags)); - fd = dup(file); +#ifdef _WIN32 + fd= my_win_dup(file); +#else + fd= dup(file); +#endif filename= (((uint) file < my_file_limit) ? my_file_info[(int) file].name : "Unknown"); DBUG_RETURN(my_register_filename(fd, filename, FILE_BY_DUP, diff --git a/mysys/my_file.c b/mysys/my_file.c index 44bacf55307..ec0c9c425ea 100644 --- a/mysys/my_file.c +++ b/mysys/my_file.c @@ -97,6 +97,7 @@ uint my_set_max_open_files(uint files) DBUG_ENTER("my_set_max_open_files"); DBUG_PRINT("enter",("files: %u my_file_limit: %u", files, my_file_limit)); + files+= MY_FILE_MIN; files= set_max_open_files(min(files, OS_FILE_LIMIT)); if (files <= MY_NFILE) DBUG_RETURN(files); diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index 44156da6ae3..879acac0111 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -41,24 +41,14 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags) DBUG_ENTER("my_fopen"); DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d", filename, flags, MyFlags)); - /* - if we are not creating, then we need to use my_access to make sure - the file exists since Windows doesn't handle files like "com1.sym" - very well - */ -#ifdef __WIN__ - if (check_if_legal_filename(filename)) - { - errno= EACCES; - fd= 0; - } - else + + make_ftype(type,flags); + +#ifdef _WIN32 + fd= my_win_fopen(filename, type); +#else + fd= fopen(filename, type); #endif - { - make_ftype(type,flags); - fd = fopen(filename, type); - } - if (fd != 0) { /* @@ -66,18 +56,20 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags) on some OS (SUNOS). Actually the filename save isn't that important so we can ignore if this doesn't work. */ - if ((uint) fileno(fd) >= my_file_limit) + + int filedesc= my_fileno(fd); + if ((uint)filedesc >= my_file_limit) { thread_safe_increment(my_stream_opened,&THR_LOCK_open); DBUG_RETURN(fd); /* safeguard */ } pthread_mutex_lock(&THR_LOCK_open); - if ((my_file_info[fileno(fd)].name = (char*) + if ((my_file_info[filedesc].name= (char*) my_strdup(filename,MyFlags))) { my_stream_opened++; my_file_total_opened++; - my_file_info[fileno(fd)].type = STREAM_BY_FOPEN; + my_file_info[filedesc].type= STREAM_BY_FOPEN; pthread_mutex_unlock(&THR_LOCK_open); DBUG_PRINT("exit",("stream: 0x%lx", (long) fd)); DBUG_RETURN(fd); @@ -99,6 +91,7 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags) /* Close a stream */ +/* Close a stream */ int my_fclose(FILE *fd, myf MyFlags) { int err,file; @@ -106,8 +99,13 @@ int my_fclose(FILE *fd, myf MyFlags) DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags)); pthread_mutex_lock(&THR_LOCK_open); - file=fileno(fd); - if ((err = fclose(fd)) < 0) + file= my_fileno(fd); +#ifndef _WIN32 + err= fclose(fd); +#else + err= my_win_fclose(fd); +#endif + if(err < 0) { my_errno=errno; if (MyFlags & (MY_FAE | MY_WME)) @@ -138,7 +136,12 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags) Filedes, Flags, MyFlags)); make_ftype(type,Flags); - if ((fd = fdopen(Filedes, type)) == 0) +#ifdef _WIN32 + fd= my_win_fdopen(Filedes, type); +#else + fd= fdopen(Filedes, type); +#endif + if (!fd) { my_errno=errno; if (MyFlags & (MY_FAE | MY_WME)) diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c index f3b5418b906..2059e1a9f18 100644 --- a/mysys/my_fstream.c +++ b/mysys/my_fstream.c @@ -56,11 +56,11 @@ size_t my_fread(FILE *stream, uchar *Buffer, size_t Count, myf MyFlags) { if (ferror(stream)) my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG), - my_filename(fileno(stream)),errno); + my_filename(my_fileno(stream)),errno); else if (MyFlags & (MY_NABP | MY_FNABP)) my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG), - my_filename(fileno(stream)),errno); + my_filename(my_fileno(stream)),errno); } my_errno=errno ? errno : -1; if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP)) @@ -142,7 +142,7 @@ size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags) if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG), - my_filename(fileno(stream)),errno); + my_filename(my_fileno(stream)),errno); } writtenbytes= (size_t) -1; /* Return that we got error */ break; @@ -182,3 +182,14 @@ my_off_t my_ftell(FILE *stream, myf MyFlags __attribute__((unused))) DBUG_PRINT("exit",("ftell: %lu",(ulong) pos)); DBUG_RETURN((my_off_t) pos); } /* my_ftell */ + + +/* Get a File corresponding to the stream*/ +int my_fileno(FILE *f) +{ +#ifdef _WIN32 + return my_win_fileno(f); +#else + return fileno(f); +#endif +} diff --git a/mysys/my_lib.c b/mysys/my_lib.c index c18d14fb549..033f8789b49 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -35,8 +35,7 @@ # if defined(HAVE_NDIR_H) # include # endif -# if defined(__WIN__) -# include +# if defined(_WIN32) # ifdef __BORLANDC__ # include # endif @@ -92,7 +91,7 @@ static int comp_names(struct fileinfo *a, struct fileinfo *b) } /* comp_names */ -#if !defined(__WIN__) +#if !defined(_WIN32) MY_DIR *my_dir(const char *path, myf MyFlags) { @@ -507,19 +506,24 @@ error: DBUG_RETURN((MY_DIR *) NULL); } /* my_dir */ -#endif /* __WIN__ */ +#endif /* _WIN32 */ /**************************************************************************** ** File status ** Note that MY_STAT is assumed to be same as struct stat ****************************************************************************/ -int my_fstat(int Filedes, MY_STAT *stat_area, + +int my_fstat(File Filedes, MY_STAT *stat_area, myf MyFlags __attribute__((unused))) { DBUG_ENTER("my_fstat"); DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags)); +#ifdef _WIN32 + DBUG_RETURN(my_win_fstat(Filedes, stat_area)); +#else DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area)); +#endif } @@ -531,11 +535,15 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags) (long) stat_area, my_flags)); if ((m_used= (stat_area == NULL))) - if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags))) + if (!(stat_area= (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags))) goto error; - if (! stat((char *) path, (struct stat *) stat_area) ) - DBUG_RETURN(stat_area); - +#ifndef _WIN32 + if (! stat((char *) path, (struct stat *) stat_area) ) + DBUG_RETURN(stat_area); +#else + if (! my_win_stat(path, stat_area) ) + DBUG_RETURN(stat_area); +#endif DBUG_PRINT("error",("Got errno: %d from stat", errno)); my_errno= errno; if (m_used) /* Free if new area */ diff --git a/mysys/my_lock.c b/mysys/my_lock.c index c0522ee849d..62f39bd3b71 100644 --- a/mysys/my_lock.c +++ b/mysys/my_lock.c @@ -22,13 +22,113 @@ #undef NO_ALARM_LOOP #endif #include -#ifdef __WIN__ -#include -#endif #ifdef __NETWARE__ #include #endif +#ifdef _WIN32 +#define WIN_LOCK_INFINITE -1 +#define WIN_LOCK_SLEEP_MILLIS 100 + +static int win_lock(File fd, int locktype, my_off_t start, my_off_t length, + int timeout_sec) +{ + LARGE_INTEGER liOffset,liLength; + DWORD dwFlags; + OVERLAPPED ov= {0}; + HANDLE hFile= (HANDLE)my_get_osfhandle(fd); + DWORD lastError= 0; + int i; + int timeout_millis= timeout_sec * 1000; + + DBUG_ENTER("win_lock"); + + liOffset.QuadPart= start; + liLength.QuadPart= length; + + ov.Offset= liOffset.LowPart; + ov.OffsetHigh= liOffset.HighPart; + + if (locktype == F_UNLCK) + { + if (UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov)) + DBUG_RETURN(0); + /* + For compatibility with fcntl implementation, ignore error, + if region was not locked + */ + if (GetLastError() == ERROR_NOT_LOCKED) + { + SetLastError(0); + DBUG_RETURN(0); + } + goto error; + } + else if (locktype == F_RDLCK) + /* read lock is mapped to a shared lock. */ + dwFlags= 0; + else + /* write lock is mapped to an exclusive lock. */ + dwFlags= LOCKFILE_EXCLUSIVE_LOCK; + + /* + Drop old lock first to avoid double locking. + During analyze of Bug#38133 (Myisamlog test fails on Windows) + I met the situation that the program myisamlog locked the file + exclusively, then additionally shared, then did one unlock, and + then blocked on an attempt to lock it exclusively again. + Unlocking before every lock fixed the problem. + Note that this introduces a race condition. When the application + wants to convert an exclusive lock into a shared one, it will now + first unlock the file and then lock it shared. A waiting exclusive + lock could step in here. For reasons described in Bug#38133 and + Bug#41124 (Server hangs on Windows with --external-locking after + INSERT...SELECT) and in the review thread at + http://lists.mysql.com/commits/60721 it seems to be the better + option than not to unlock here. + If one day someone notices a way how to do file lock type changes + on Windows without unlocking before taking the new lock, please + change this code accordingly to fix the race condition. + */ + if (!UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov) && + (GetLastError() != ERROR_NOT_LOCKED)) + goto error; + + if (timeout_sec == WIN_LOCK_INFINITE) + { + if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov)) + DBUG_RETURN(0); + goto error; + } + + dwFlags|= LOCKFILE_FAIL_IMMEDIATELY; + timeout_millis= timeout_sec * 1000; + /* Try lock in a loop, until the lock is acquired or timeout happens */ + for(i= 0; ;i+= WIN_LOCK_SLEEP_MILLIS) + { + if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov)) + DBUG_RETURN(0); + + if (GetLastError() != ERROR_LOCK_VIOLATION) + goto error; + + if (i >= timeout_millis) + break; + Sleep(WIN_LOCK_SLEEP_MILLIS); + } + + /* timeout */ + errno= EAGAIN; + DBUG_RETURN(-1); + +error: + my_osmaperr(GetLastError()); + DBUG_RETURN(-1); +} +#endif + + + /* Lock a part of a file @@ -48,8 +148,9 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, #ifdef __NETWARE__ int nxErrno; #endif + DBUG_ENTER("my_lock"); - DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d", + DBUG_PRINT("my",("fd: %d Op: %d start: %ld Length: %ld MyFlags: %d", fd,locktype,(long) start,(long) length,MyFlags)); #ifdef VMS DBUG_RETURN(0); @@ -97,29 +198,16 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, DBUG_RETURN(0); } } -#elif defined(HAVE_LOCKING) - /* Windows */ +#elif defined(_WIN32) { - my_bool error= FALSE; - pthread_mutex_lock(&my_file_info[fd].mutex); - if (MyFlags & MY_SEEK_NOT_DONE) - { - if( my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)) - == MY_FILEPOS_ERROR ) - { - /* - If my_seek fails my_errno will already contain an error code; - just unlock and return error code. - */ - DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno)); - pthread_mutex_unlock(&my_file_info[fd].mutex); - DBUG_RETURN(-1); - } - } - error= locking(fd,locktype,(ulong) length) && errno != EINVAL; - pthread_mutex_unlock(&my_file_info[fd].mutex); - if (!error) - DBUG_RETURN(0); + int timeout_sec; + if (MyFlags & MY_DONT_WAIT) + timeout_sec= 0; + else + timeout_sec= WIN_LOCK_INFINITE; + + if(win_lock(fd, locktype, start, length, timeout_sec) == 0) + DBUG_RETURN(0); } #else #if defined(HAVE_FCNTL) diff --git a/mysys/my_mmap.c b/mysys/my_mmap.c index 023a06fd896..303d8efaf30 100644 --- a/mysys/my_mmap.c +++ b/mysys/my_mmap.c @@ -27,17 +27,17 @@ int my_msync(int fd, void *addr, size_t len, int flags) return my_sync(fd, MYF(0)); } -#elif defined(__WIN__) +#elif defined(_WIN32) static SECURITY_ATTRIBUTES mmap_security_attributes= {sizeof(SECURITY_ATTRIBUTES), 0, TRUE}; void *my_mmap(void *addr, size_t len, int prot, - int flags, int fd, my_off_t offset) + int flags, File fd, my_off_t offset) { HANDLE hFileMap; LPVOID ptr; - HANDLE hFile= (HANDLE)_get_osfhandle(fd); + HANDLE hFile= (HANDLE)my_get_osfhandle(fd); if (hFile == INVALID_HANDLE_VALUE) return MAP_FAILED; diff --git a/mysys/my_open.c b/mysys/my_open.c index fe7f65c450b..79a4da242f9 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -17,9 +17,7 @@ #include "mysys_err.h" #include #include -#if defined(__WIN__) -#include -#endif + /* Open a file @@ -43,29 +41,8 @@ File my_open(const char *FileName, int Flags, myf MyFlags) DBUG_ENTER("my_open"); DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d", FileName, Flags, MyFlags)); -#if defined(__WIN__) - /* - Check that we don't try to open or create a file name that may - cause problems for us in the future (like PRN) - */ - if (check_if_legal_filename(FileName)) - { - errno= EACCES; - DBUG_RETURN(my_register_filename(-1, FileName, FILE_BY_OPEN, - EE_FILENOTFOUND, MyFlags)); - } -#ifndef __WIN__ - if (Flags & O_SHARE) - fd = sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO, - MY_S_IREAD | MY_S_IWRITE); - else - fd = open((char *) FileName, Flags | O_BINARY, - MY_S_IREAD | MY_S_IWRITE); -#else - fd= my_sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO, - MY_S_IREAD | MY_S_IWRITE); -#endif - +#if defined(_WIN32) + fd= my_win_open(FileName, Flags); #elif !defined(NO_OPEN_3) fd = open(FileName, Flags, my_umask); /* Normal unix */ #else @@ -94,11 +71,14 @@ int my_close(File fd, myf MyFlags) DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags)); pthread_mutex_lock(&THR_LOCK_open); +#ifndef _WIN32 do { err= close(fd); } while (err == -1 && errno == EINTR); - +#else + err= my_win_close(fd); +#endif if (err) { DBUG_PRINT("error",("Got error %d on close",err)); @@ -109,7 +89,7 @@ int my_close(File fd, myf MyFlags) if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN) { my_free(my_file_info[fd].name, MYF(0)); -#if defined(THREAD) && !defined(HAVE_PREAD) +#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32) pthread_mutex_destroy(&my_file_info[fd].mutex); #endif my_file_info[fd].type = UNOPEN; @@ -141,11 +121,11 @@ File my_register_filename(File fd, const char *FileName, enum file_type type_of_file, uint error_message_number, myf MyFlags) { DBUG_ENTER("my_register_filename"); - if ((int) fd >= 0) + if ((int) fd >= MY_FILE_MIN) { if ((uint) fd >= my_file_limit) { -#if defined(THREAD) && !defined(HAVE_PREAD) +#if defined(THREAD) && !defined(HAVE_PREAD) my_errno= EMFILE; #else thread_safe_increment(my_file_opened,&THR_LOCK_open); @@ -160,7 +140,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type my_file_opened++; my_file_total_opened++; my_file_info[fd].type = type_of_file; -#if defined(THREAD) && !defined(HAVE_PREAD) +#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32) pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST); #endif pthread_mutex_unlock(&THR_LOCK_open); @@ -187,188 +167,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type DBUG_RETURN(-1); } -#ifdef __WIN__ -extern void __cdecl _dosmaperr(unsigned long); - -/* - Open a file with sharing. Similar to _sopen() from libc, but allows managing - share delete on win32 - - SYNOPSIS - my_sopen() - path fully qualified file name - oflag operation flags - shflag share flag - pmode permission flags - - RETURN VALUE - File descriptor of opened file if success - -1 and sets errno if fails. -*/ - -File my_sopen(const char *path, int oflag, int shflag, int pmode) -{ - int fh; /* handle of opened file */ - int mask; - HANDLE osfh; /* OS handle of opened file */ - DWORD fileaccess; /* OS file access (requested) */ - DWORD fileshare; /* OS file sharing mode */ - DWORD filecreate; /* OS method of opening/creating */ - DWORD fileattrib; /* OS file attribute flags */ - SECURITY_ATTRIBUTES SecurityAttributes; - - SecurityAttributes.nLength= sizeof(SecurityAttributes); - SecurityAttributes.lpSecurityDescriptor= NULL; - SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT); - - /* - * decode the access flags - */ - switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { - case _O_RDONLY: /* read access */ - fileaccess= GENERIC_READ; - break; - case _O_WRONLY: /* write access */ - fileaccess= GENERIC_WRITE; - break; - case _O_RDWR: /* read and write access */ - fileaccess= GENERIC_READ | GENERIC_WRITE; - break; - default: /* error, bad oflag */ - errno= EINVAL; - _doserrno= 0L; /* not an OS error */ - return -1; - } - - /* - * decode sharing flags - */ - switch (shflag) { - case _SH_DENYRW: /* exclusive access except delete */ - fileshare= FILE_SHARE_DELETE; - break; - case _SH_DENYWR: /* share read and delete access */ - fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE; - break; - case _SH_DENYRD: /* share write and delete access */ - fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE; - break; - case _SH_DENYNO: /* share read, write and delete access */ - fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - break; - case _SH_DENYRWD: /* exclusive access */ - fileshare= 0L; - break; - case _SH_DENYWRD: /* share read access */ - fileshare= FILE_SHARE_READ; - break; - case _SH_DENYRDD: /* share write access */ - fileshare= FILE_SHARE_WRITE; - break; - case _SH_DENYDEL: /* share read and write access */ - fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE; - break; - default: /* error, bad shflag */ - errno= EINVAL; - _doserrno= 0L; /* not an OS error */ - return -1; - } - - /* - * decode open/create method flags - */ - switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) { - case 0: - case _O_EXCL: /* ignore EXCL w/o CREAT */ - filecreate= OPEN_EXISTING; - break; - - case _O_CREAT: - filecreate= OPEN_ALWAYS; - break; - - case _O_CREAT | _O_EXCL: - case _O_CREAT | _O_TRUNC | _O_EXCL: - filecreate= CREATE_NEW; - break; - - case _O_TRUNC: - case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */ - filecreate= TRUNCATE_EXISTING; - break; - - case _O_CREAT | _O_TRUNC: - filecreate= CREATE_ALWAYS; - break; - - default: - /* this can't happen ... all cases are covered */ - errno= EINVAL; - _doserrno= 0L; - return -1; - } - - /* - * decode file attribute flags if _O_CREAT was specified - */ - fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */ - if (oflag & _O_CREAT) - { - _umask((mask= _umask(0))); - - if (!((pmode & ~mask) & _S_IWRITE)) - fileattrib= FILE_ATTRIBUTE_READONLY; - } - - /* - * Set temporary file (delete-on-close) attribute if requested. - */ - if (oflag & _O_TEMPORARY) - { - fileattrib|= FILE_FLAG_DELETE_ON_CLOSE; - fileaccess|= DELETE; - } - - /* - * Set temporary file (delay-flush-to-disk) attribute if requested. - */ - if (oflag & _O_SHORT_LIVED) - fileattrib|= FILE_ATTRIBUTE_TEMPORARY; - - /* - * Set sequential or random access attribute if requested. - */ - if (oflag & _O_SEQUENTIAL) - fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN; - else if (oflag & _O_RANDOM) - fileattrib|= FILE_FLAG_RANDOM_ACCESS; - - /* - * try to open/create the file - */ - if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes, - filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE) - { - /* - * OS call to open/create file failed! map the error, release - * the lock, and return -1. note that it's not necessary to - * call _free_osfhnd (it hasn't been used yet). - */ - _dosmaperr(GetLastError()); /* map error */ - return -1; /* return error to caller */ - } - - if ((fh= _open_osfhandle((intptr_t)osfh, - oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1) - { - _dosmaperr(GetLastError()); /* map error */ - CloseHandle(osfh); - } - - return fh; /* return handle */ -} -#endif /* __WIN__ */ #ifdef EXTRA_DEBUG diff --git a/mysys/my_pread.c b/mysys/my_pread.c index 3f62f150c91..eaabcb1b728 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -15,11 +15,15 @@ #include "mysys_priv.h" #include "mysys_err.h" +#include "my_base.h" +#include #include -#ifdef HAVE_PREAD +#if defined (HAVE_PREAD) && !defined(_WIN32) #include #endif + + /* Read a chunk of bytes from a file from a given position @@ -46,27 +50,39 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset, { size_t readbytes; int error= 0; +#if !defined (HAVE_PREAD) && !defined (_WIN32) + int save_errno; +#endif DBUG_ENTER("my_pread"); - DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d", - Filedes, (ulong) offset, (long) Buffer, (uint) Count, - MyFlags)); + DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d", + Filedes, (ulonglong)offset, Buffer, (ulong)Count, MyFlags)); for (;;) { -#ifndef __WIN__ - errno=0; /* Linux doesn't reset this */ -#endif -#ifndef HAVE_PREAD + errno= 0; /* Linux, Windows don't reset this on EOF/success */ +#if !defined (HAVE_PREAD) && !defined (_WIN32) pthread_mutex_lock(&my_file_info[Filedes].mutex); readbytes= (uint) -1; error= (lseek(Filedes, offset, MY_SEEK_SET) == (my_off_t) -1 || - (readbytes= read(Filedes, Buffer, (uint) Count)) != Count); + (readbytes= read(Filedes, Buffer, Count)) != Count); + save_errno= errno; pthread_mutex_unlock(&my_file_info[Filedes].mutex); + if (error) + errno= save_errno; #else - if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count))) - my_errno= errno ? errno : -1; +#if defined(_WIN32) + readbytes= my_win_pread(Filedes, Buffer, Count, offset); +#else + readbytes= pread(Filedes, Buffer, Count, offset); #endif - if (error || readbytes != Count) + error= (readbytes != Count); +#endif + if(error) { + my_errno= errno ? errno : -1; + if (errno == 0 || (readbytes != (size_t) -1 && + (MyFlags & (MY_NABP | MY_FNABP)))) + my_errno= HA_ERR_FILE_TOO_SHORT; + DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d", (int) readbytes, (uint) Count,Filedes,my_errno)); #ifdef THREAD @@ -79,19 +95,19 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset, #endif if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { - if (readbytes == (size_t) -1) - my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG), - my_filename(Filedes),my_errno); - else if (MyFlags & (MY_NABP | MY_FNABP)) - my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG), - my_filename(Filedes),my_errno); + if (readbytes == (size_t) -1) + my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG), + my_filename(Filedes),my_errno); + else if (MyFlags & (MY_NABP | MY_FNABP)) + my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG), + my_filename(Filedes),my_errno); } if (readbytes == (size_t) -1 || (MyFlags & (MY_FNABP | MY_NABP))) - DBUG_RETURN(MY_FILE_ERROR); /* Return with error */ + DBUG_RETURN(MY_FILE_ERROR); /* Return with error */ } if (MyFlags & (MY_NABP | MY_FNABP)) - DBUG_RETURN(0); /* Read went ok; Return 0 */ - DBUG_RETURN(readbytes); /* purecov: inspected */ + DBUG_RETURN(0); /* Read went ok; Return 0 */ + DBUG_RETURN(readbytes); /* purecov: inspected */ } } /* my_pread */ @@ -117,42 +133,45 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset, # Number of bytes read */ -size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count, +size_t my_pwrite(File Filedes, const uchar *Buffer, size_t Count, my_off_t offset, myf MyFlags) { - size_t writenbytes, written; + size_t writtenbytes, written; uint errors; + DBUG_ENTER("my_pwrite"); - DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d", - Filedes, (ulong) offset, (long) Buffer, (uint) Count, - MyFlags)); + DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d", + Filedes, offset, Buffer, (ulong)Count, MyFlags)); errors= 0; written= 0; for (;;) { -#ifndef HAVE_PREAD +#if !defined (HAVE_PREAD) && !defined (_WIN32) int error; - writenbytes= (size_t) -1; + writtenbytes= (size_t) -1; pthread_mutex_lock(&my_file_info[Filedes].mutex); error= (lseek(Filedes, offset, MY_SEEK_SET) != (my_off_t) -1 && - (writenbytes = write(Filedes, Buffer, (uint) Count)) == Count); + (writtenbytes= write(Filedes, Buffer, Count)) == Count); pthread_mutex_unlock(&my_file_info[Filedes].mutex); if (error) break; +#elif defined (_WIN32) + writtenbytes= my_win_pwrite(Filedes, Buffer, Count, offset); #else - if ((writenbytes= pwrite(Filedes, Buffer, Count,offset)) == Count) + writtenbytes= pwrite(Filedes, Buffer, Count, offset); +#endif + if(writtenbytes == Count) break; my_errno= errno; -#endif - if (writenbytes != (size_t) -1) - { /* Safegueard */ - written+=writenbytes; - Buffer+=writenbytes; - Count-=writenbytes; - offset+=writenbytes; + if (writtenbytes != (size_t) -1) + { + written+= writtenbytes; + Buffer+= writtenbytes; + Count-= writtenbytes; + offset+= writtenbytes; } - DBUG_PRINT("error",("Write only %u bytes", (uint) writenbytes)); + DBUG_PRINT("error",("Write only %u bytes", (uint) writtenbytes)); #ifndef NO_BACKGROUND #ifdef THREAD if (my_thread_var->abort) @@ -165,15 +184,15 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count, errors++; continue; } - if ((writenbytes && writenbytes != (size_t) -1) || my_errno == EINTR) + if ((writtenbytes && writtenbytes != (size_t) -1) || my_errno == EINTR) continue; /* Retry */ #endif if (MyFlags & (MY_NABP | MY_FNABP)) { if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { - my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG), - my_filename(Filedes),my_errno); + my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG), + my_filename(Filedes),my_errno); } DBUG_RETURN(MY_FILE_ERROR); /* Error on read */ } @@ -183,5 +202,5 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count, DBUG_EXECUTE_IF("check", my_seek(Filedes, -1, SEEK_SET, MYF(0));); if (MyFlags & (MY_NABP | MY_FNABP)) DBUG_RETURN(0); /* Want only errors */ - DBUG_RETURN(writenbytes+written); /* purecov: inspected */ + DBUG_RETURN(writtenbytes+written); /* purecov: inspected */ } /* my_pwrite */ diff --git a/mysys/my_quick.c b/mysys/my_quick.c index 0ba20a5bdee..b93e7e17224 100644 --- a/mysys/my_quick.c +++ b/mysys/my_quick.c @@ -19,11 +19,19 @@ #include "my_nosys.h" +#ifdef _WIN32 +extern size_t my_win_read(File Filedes,uchar *Buffer,size_t Count); +#endif + size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags) { size_t readbytes; - - if ((readbytes = read(Filedes, Buffer, (uint) Count)) != Count) +#ifdef _WIN32 + readbytes= my_win_read(Filedes, Buffer, Count); +#else + readbytes= read(Filedes, Buffer, Count); +#endif + if(readbytes != Count) { #ifndef DBUG_OFF if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR) @@ -40,8 +48,13 @@ size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags) } -size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count) + +size_t my_quick_write(File Filedes, const uchar *Buffer, size_t Count) { +#ifdef _WIN32 + return my_win_write(Filedes, Buffer, Count); +#else + #ifndef DBUG_OFF size_t writtenbytes; #endif @@ -50,7 +63,7 @@ size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count) #ifndef DBUG_OFF writtenbytes = #endif - (size_t) write(Filedes,Buffer, (uint) Count)) != Count) + (size_t) write(Filedes,Buffer,Count)) != Count) { #ifndef DBUG_OFF if ((writtenbytes == 0 || writtenbytes == (size_t) -1) && errno == EINTR) @@ -64,4 +77,5 @@ size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count) return (size_t) -1; } return 0; +#endif } diff --git a/mysys/my_read.c b/mysys/my_read.c index 0c302d5b227..75f9dd64f1d 100644 --- a/mysys/my_read.c +++ b/mysys/my_read.c @@ -15,9 +15,9 @@ #include "mysys_priv.h" #include "mysys_err.h" +#include #include - /* Read a chunk of bytes from a file with retry's if needed @@ -37,16 +37,25 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags) { size_t readbytes, save_count; DBUG_ENTER("my_read"); - DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d", - Filedes, (long) Buffer, (ulong) Count, MyFlags)); + DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %d", + Filedes, Buffer, (ulong) Count, MyFlags)); save_count= Count; for (;;) { - errno= 0; /* Linux doesn't reset this */ - if ((readbytes= read(Filedes, Buffer, (uint) Count)) != Count) + errno= 0; /* Linux, Windows don't reset this on EOF/success */ +#ifdef _WIN32 + readbytes= my_win_read(Filedes, Buffer, Count); +#else + readbytes= read(Filedes, Buffer, Count); +#endif + + if (readbytes != Count) { - my_errno= errno ? errno : -1; + my_errno= errno; + if (errno == 0 || (readbytes != (size_t) -1 && + (MyFlags & (MY_NABP | MY_FNABP)))) + my_errno= HA_ERR_FILE_TOO_SHORT; DBUG_PRINT("warning",("Read only %d bytes off %lu from %d, errno: %d", (int) readbytes, (ulong) Count, Filedes, my_errno)); diff --git a/mysys/my_seek.c b/mysys/my_seek.c index 2c661baeff7..8502c259353 100644 --- a/mysys/my_seek.c +++ b/mysys/my_seek.c @@ -45,36 +45,30 @@ my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags __attribute__((unused))) { - reg1 os_off_t newpos= -1; + os_off_t newpos= -1; DBUG_ENTER("my_seek"); - DBUG_PRINT("my",("Fd: %d Hpos: %lu Pos: %lu Whence: %d MyFlags: %d", - fd, (ulong) (((ulonglong) pos) >> 32), (ulong) pos, - whence, MyFlags)); + DBUG_PRINT("my",("fd: %d Pos: %llu Whence: %d MyFlags: %d", + fd, (ulonglong) pos, whence, MyFlags)); DBUG_ASSERT(pos != MY_FILEPOS_ERROR); /* safety check */ /* Make sure we are using a valid file descriptor! */ DBUG_ASSERT(fd != -1); -#if defined(THREAD) && !defined(HAVE_PREAD) - if (MyFlags & MY_THREADSAFE) - { - pthread_mutex_lock(&my_file_info[fd].mutex); - newpos= lseek(fd, pos, whence); - pthread_mutex_unlock(&my_file_info[fd].mutex); - } - else +#if defined (_WIN32) + newpos= my_win_lseek(fd, pos, whence); +#else + newpos= lseek(fd, pos, whence); #endif - newpos= lseek(fd, pos, whence); if (newpos == (os_off_t) -1) { - my_errno=errno; - DBUG_PRINT("error",("lseek: %lu errno: %d", (ulong) newpos,errno)); + my_errno= errno; + DBUG_PRINT("error",("lseek: %llu errno: %d", (ulonglong) newpos,errno)); DBUG_RETURN(MY_FILEPOS_ERROR); } if ((my_off_t) newpos != pos) { - DBUG_PRINT("exit",("pos: %lu", (ulong) newpos)); + DBUG_PRINT("exit",("pos: %llu", (ulonglong) newpos)); } DBUG_RETURN((my_off_t) newpos); } /* my_seek */ @@ -87,15 +81,15 @@ my_off_t my_tell(File fd, myf MyFlags __attribute__((unused))) { os_off_t pos; DBUG_ENTER("my_tell"); - DBUG_PRINT("my",("Fd: %d MyFlags: %d",fd, MyFlags)); + DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags)); DBUG_ASSERT(fd >= 0); -#ifdef HAVE_TELL - pos=tell(fd); +#if defined (HAVE_TELL) && !defined (_WIN32) + pos= tell(fd); #else - pos=lseek(fd, 0L, MY_SEEK_CUR); + pos= my_seek(fd, 0L, MY_SEEK_CUR,0); #endif if (pos == (os_off_t) -1) - my_errno=errno; - DBUG_PRINT("exit",("pos: %lu", (ulong) pos)); + my_errno= errno; + DBUG_PRINT("exit",("pos: %llu", (ulonglong) pos)); DBUG_RETURN((my_off_t) pos); } /* my_tell */ diff --git a/mysys/my_static.c b/mysys/my_static.c index d0c20da828a..1ddf3524052 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -35,7 +35,7 @@ int NEAR my_umask=0664, NEAR my_umask_dir=0777; #ifndef THREAD int NEAR my_errno=0; #endif -struct st_my_file_info my_file_info_default[MY_NFILE]= {{0,UNOPEN}}; +struct st_my_file_info my_file_info_default[MY_NFILE]; uint my_file_limit= MY_NFILE; struct st_my_file_info *my_file_info= my_file_info_default; diff --git a/mysys/my_sync.c b/mysys/my_sync.c index ba6964b00d6..7b2112fa032 100644 --- a/mysys/my_sync.c +++ b/mysys/my_sync.c @@ -62,8 +62,8 @@ int my_sync(File fd, myf my_flags) res= fdatasync(fd); #elif defined(HAVE_FSYNC) res= fsync(fd); -#elif defined(__WIN__) - res= _commit(fd); +#elif defined(_WIN32) + res= my_win_fsync(fd); #else #error Cannot find a way to sync a file, durability in danger res= 0; /* No sync (strange OS) */ diff --git a/mysys/my_winerr.c b/mysys/my_winerr.c new file mode 100644 index 00000000000..534078b6737 --- /dev/null +++ b/mysys/my_winerr.c @@ -0,0 +1,123 @@ +/* Copyright (C) 2008 MySQL AB + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Convert Windows API error (GetLastError() to Posix equivalent (errno) + The exported function my_osmaperr() is modelled after and borrows + heavily from undocumented _dosmaperr()(found of the static Microsoft C runtime). +*/ + +#include +#include + + +struct errentry +{ + unsigned long oscode; /* OS return value */ + int sysv_errno; /* System V error code */ +}; + +static struct errentry errtable[]= { + { ERROR_INVALID_FUNCTION, EINVAL }, /* 1 */ + { ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 */ + { ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 */ + { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 */ + { ERROR_ACCESS_DENIED, EACCES }, /* 5 */ + { ERROR_INVALID_HANDLE, EBADF }, /* 6 */ + { ERROR_ARENA_TRASHED, ENOMEM }, /* 7 */ + { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 */ + { ERROR_INVALID_BLOCK, ENOMEM }, /* 9 */ + { ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 */ + { ERROR_BAD_FORMAT, ENOEXEC }, /* 11 */ + { ERROR_INVALID_ACCESS, EINVAL }, /* 12 */ + { ERROR_INVALID_DATA, EINVAL }, /* 13 */ + { ERROR_INVALID_DRIVE, ENOENT }, /* 15 */ + { ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */ + { ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */ + { ERROR_NO_MORE_FILES, ENOENT }, /* 18 */ + { ERROR_LOCK_VIOLATION, EACCES }, /* 33 */ + { ERROR_BAD_NETPATH, ENOENT }, /* 53 */ + { ERROR_NETWORK_ACCESS_DENIED, EACCES }, /* 65 */ + { ERROR_BAD_NET_NAME, ENOENT }, /* 67 */ + { ERROR_FILE_EXISTS, EEXIST }, /* 80 */ + { ERROR_CANNOT_MAKE, EACCES }, /* 82 */ + { ERROR_FAIL_I24, EACCES }, /* 83 */ + { ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */ + { ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */ + { ERROR_DRIVE_LOCKED, EACCES }, /* 108 */ + { ERROR_BROKEN_PIPE, EPIPE }, /* 109 */ + { ERROR_DISK_FULL, ENOSPC }, /* 112 */ + { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */ + { ERROR_INVALID_HANDLE, EINVAL }, /* 124 */ + { ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */ + { ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */ + { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */ + { ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */ + { ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */ + { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */ + { ERROR_NOT_LOCKED, EACCES }, /* 158 */ + { ERROR_BAD_PATHNAME, ENOENT }, /* 161 */ + { ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */ + { ERROR_LOCK_FAILED, EACCES }, /* 167 */ + { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */ + { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */ + { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */ + { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */ +}; + +/* size of the table */ +#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0])) + +/* The following two constants must be the minimum and maximum +values in the (contiguous) range of Exec Failure errors. */ +#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG +#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN + +/* These are the low and high value in the range of errors that are +access violations */ +#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT +#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED + + +static int get_errno_from_oserr(unsigned long oserrno) +{ + int i; + + /* check the table for the OS error code */ + for (i= 0; i < ERRTABLESIZE; ++i) + { + if (oserrno == errtable[i].oscode) + { + return errtable[i].sysv_errno; + } + } + + /* The error code wasn't in the table. We check for a range of */ + /* EACCES errors or exec failure errors (ENOEXEC). Otherwise */ + /* EINVAL is returned. */ + + if (oserrno >= MIN_EACCES_RANGE && oserrno <= MAX_EACCES_RANGE) + return EACCES; + else if (oserrno >= MIN_EXEC_ERROR && oserrno <= MAX_EXEC_ERROR) + return ENOEXEC; + else + return EINVAL; +} + +/* Set errno corresponsing to GetLastError() value */ +void my_osmaperr ( unsigned long oserrno) +{ + errno= get_errno_from_oserr(oserrno); +} diff --git a/mysys/my_winfile.c b/mysys/my_winfile.c new file mode 100644 index 00000000000..de1d747c967 --- /dev/null +++ b/mysys/my_winfile.c @@ -0,0 +1,671 @@ +/* Copyright (C) 2008 MySQL AB + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + The purpose of this file is to provide implementation of file IO routines on + Windows that can be thought as drop-in replacement for corresponding C runtime + functionality. + + Compared to Windows CRT, this one + - does not have the same file descriptor + limitation (default is 16384 and can be increased further, whereas CRT poses + a hard limit of 2048 file descriptors) + - the file operations are not serialized + - positional IO pread/pwrite is ported here. + - no text mode for files, all IO is "binary" + + Naming convention: + All routines are prefixed with my_win_, e.g Posix open() is implemented with + my_win_open() + + Implemented are + - POSIX routines(e.g open, read, lseek ...) + - Some ANSI C stream routines (fopen, fdopen, fileno, fclose) + - Windows CRT equvalients (my_get_osfhandle, open_osfhandle) + + Worth to note: + - File descriptors used here are located in a range that is not compatible + with CRT on purpose. Attempt to use a file descriptor from Windows CRT library + range in my_win_* function will be punished with DBUG_ASSERT() + + - File streams (FILE *) are actually from the C runtime. The routines provided + here are useful only in scernarios that use low-level IO with my_win_fileno() +*/ + +#ifdef _WIN32 + +#include "mysys_priv.h" +#include +#include + +/* Associates a file descriptor with an existing operating-system file handle.*/ +File my_open_osfhandle(HANDLE handle, int oflag) +{ + int offset= -1; + uint i; + DBUG_ENTER("my_open_osfhandle"); + + pthread_mutex_lock(&THR_LOCK_open); + for(i= MY_FILE_MIN; i < my_file_limit;i++) + { + if(my_file_info[i].fhandle == 0) + { + struct st_my_file_info *finfo= &(my_file_info[i]); + finfo->type= FILE_BY_OPEN; + finfo->fhandle= handle; + finfo->oflag= oflag; + offset= i; + break; + } + } + pthread_mutex_unlock(&THR_LOCK_open); + if(offset == -1) + errno= EMFILE; /* to many file handles open */ + DBUG_RETURN(offset); +} + + +static void invalidate_fd(File fd) +{ + DBUG_ENTER("invalidate_fd"); + DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit); + my_file_info[fd].fhandle= 0; + DBUG_VOID_RETURN; +} + + +/* Get Windows handle for a file descriptor */ +HANDLE my_get_osfhandle(File fd) +{ + DBUG_ENTER("my_get_osfhandle"); + DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit); + DBUG_RETURN(my_file_info[fd].fhandle); +} + + +static int my_get_open_flags(File fd) +{ + DBUG_ENTER("my_get_osfhandle"); + DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit); + DBUG_RETURN(my_file_info[fd].oflag); +} + + +/* + Open a file with sharing. Similar to _sopen() from libc, but allows managing + share delete on win32 + + SYNOPSIS + my_win_sopen() + path file name + oflag operation flags + shflag share flag + pmode permission flags + + RETURN VALUE + File descriptor of opened file if success + -1 and sets errno if fails. +*/ + +File my_win_sopen(const char *path, int oflag, int shflag, int pmode) +{ + int fh; /* handle of opened file */ + int mask; + HANDLE osfh; /* OS handle of opened file */ + DWORD fileaccess; /* OS file access (requested) */ + DWORD fileshare; /* OS file sharing mode */ + DWORD filecreate; /* OS method of opening/creating */ + DWORD fileattrib; /* OS file attribute flags */ + SECURITY_ATTRIBUTES SecurityAttributes; + + DBUG_ENTER("my_win_sopen"); + + if (check_if_legal_filename(path)) + { + errno= EACCES; + DBUG_RETURN(-1); + } + SecurityAttributes.nLength= sizeof(SecurityAttributes); + SecurityAttributes.lpSecurityDescriptor= NULL; + SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT); + + /* decode the access flags */ + switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: /* read access */ + fileaccess= GENERIC_READ; + break; + case _O_WRONLY: /* write access */ + fileaccess= GENERIC_WRITE; + break; + case _O_RDWR: /* read and write access */ + fileaccess= GENERIC_READ | GENERIC_WRITE; + break; + default: /* error, bad oflag */ + errno= EINVAL; + DBUG_RETURN(-1); + } + + /* decode sharing flags */ + switch (shflag) { + case _SH_DENYRW: /* exclusive access except delete */ + fileshare= FILE_SHARE_DELETE; + break; + case _SH_DENYWR: /* share read and delete access */ + fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE; + break; + case _SH_DENYRD: /* share write and delete access */ + fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + case _SH_DENYNO: /* share read, write and delete access */ + fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + case _SH_DENYRWD: /* exclusive access */ + fileshare= 0L; + break; + case _SH_DENYWRD: /* share read access */ + fileshare= FILE_SHARE_READ; + break; + case _SH_DENYRDD: /* share write access */ + fileshare= FILE_SHARE_WRITE; + break; + case _SH_DENYDEL: /* share read and write access */ + fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE; + break; + default: /* error, bad shflag */ + errno= EINVAL; + DBUG_RETURN(-1); + } + + /* decode open/create method flags */ + switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + case 0: + case _O_EXCL: /* ignore EXCL w/o CREAT */ + filecreate= OPEN_EXISTING; + break; + + case _O_CREAT: + filecreate= OPEN_ALWAYS; + break; + + case _O_CREAT | _O_EXCL: + case _O_CREAT | _O_TRUNC | _O_EXCL: + filecreate= CREATE_NEW; + break; + + case _O_TRUNC: + case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */ + filecreate= TRUNCATE_EXISTING; + break; + + case _O_CREAT | _O_TRUNC: + filecreate= CREATE_ALWAYS; + break; + + default: + /* this can't happen ... all cases are covered */ + errno= EINVAL; + DBUG_RETURN(-1); + } + + /* decode file attribute flags if _O_CREAT was specified */ + fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */ + if (oflag & _O_CREAT) + { + _umask((mask= _umask(0))); + + if (!((pmode & ~mask) & _S_IWRITE)) + fileattrib= FILE_ATTRIBUTE_READONLY; + } + + /* Set temporary file (delete-on-close) attribute if requested. */ + if (oflag & _O_TEMPORARY) + { + fileattrib|= FILE_FLAG_DELETE_ON_CLOSE; + fileaccess|= DELETE; + } + + /* Set temporary file (delay-flush-to-disk) attribute if requested.*/ + if (oflag & _O_SHORT_LIVED) + fileattrib|= FILE_ATTRIBUTE_TEMPORARY; + + /* Set sequential or random access attribute if requested. */ + if (oflag & _O_SEQUENTIAL) + fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN; + else if (oflag & _O_RANDOM) + fileattrib|= FILE_FLAG_RANDOM_ACCESS; + + /* try to open/create the file */ + if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes, + filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE) + { + /* + OS call to open/create file failed! map the error, release + the lock, and return -1. note that it's not necessary to + call _free_osfhnd (it hasn't been used yet). + */ + my_osmaperr(GetLastError()); /* map error */ + DBUG_RETURN(-1); /* return error to caller */ + } + + if ((fh= my_open_osfhandle(osfh, + oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1) + { + CloseHandle(osfh); + } + + DBUG_RETURN(fh); /* return handle */ +} + + +File my_win_open(const char *path, int flags) +{ + DBUG_ENTER("my_win_open"); + DBUG_RETURN(my_win_sopen((char *) path, flags | _O_BINARY, _SH_DENYNO, + _S_IREAD | S_IWRITE)); +} + + +int my_win_close(File fd) +{ + DBUG_ENTER("my_win_close"); + if(CloseHandle(my_get_osfhandle(fd))) + { + invalidate_fd(fd); + DBUG_RETURN(0); + } + my_osmaperr(GetLastError()); + DBUG_RETURN(-1); +} + + +size_t my_win_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset) +{ + DWORD nBytesRead; + HANDLE hFile; + OVERLAPPED ov= {0}; + LARGE_INTEGER li; + + DBUG_ENTER("my_win_pread"); + + if(!Count) + DBUG_RETURN(0); +#ifdef _WIN64 + if(Count > UINT_MAX) + Count= UINT_MAX; +#endif + + hFile= (HANDLE)my_get_osfhandle(Filedes); + li.QuadPart= offset; + ov.Offset= li.LowPart; + ov.OffsetHigh= li.HighPart; + + if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, &ov)) + { + DWORD lastError= GetLastError(); + /* + ERROR_BROKEN_PIPE is returned when no more data coming + through e.g. a command pipe in windows : see MSDN on ReadFile. + */ + if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE) + DBUG_RETURN(0); /*return 0 at EOF*/ + my_osmaperr(lastError); + DBUG_RETURN(-1); + } + DBUG_RETURN(nBytesRead); +} + + +size_t my_win_read(File Filedes, uchar *Buffer, size_t Count) +{ + DWORD nBytesRead; + HANDLE hFile; + + DBUG_ENTER("my_win_read"); + if(!Count) + DBUG_RETURN(0); +#ifdef _WIN64 + if(Count > UINT_MAX) + Count= UINT_MAX; +#endif + + hFile= (HANDLE)my_get_osfhandle(Filedes); + + if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, NULL)) + { + DWORD lastError= GetLastError(); + /* + ERROR_BROKEN_PIPE is returned when no more data coming + through e.g. a command pipe in windows : see MSDN on ReadFile. + */ + if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE) + DBUG_RETURN(0); /*return 0 at EOF*/ + my_osmaperr(lastError); + DBUG_RETURN(-1); + } + DBUG_RETURN(nBytesRead); +} + + +size_t my_win_pwrite(File Filedes, const uchar *Buffer, size_t Count, + my_off_t offset) +{ + DWORD nBytesWritten; + HANDLE hFile; + OVERLAPPED ov= {0}; + LARGE_INTEGER li; + + DBUG_ENTER("my_win_pwrite"); + DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count: %zd, offset: %llu", + Filedes, Buffer, Count, (ulonglong)offset)); + + if(!Count) + DBUG_RETURN(0); + +#ifdef _WIN64 + if(Count > UINT_MAX) + Count= UINT_MAX; +#endif + + hFile= (HANDLE)my_get_osfhandle(Filedes); + li.QuadPart= offset; + ov.Offset= li.LowPart; + ov.OffsetHigh= li.HighPart; + + if(!WriteFile(hFile, Buffer, (DWORD)Count, &nBytesWritten, &ov)) + { + my_osmaperr(GetLastError()); + DBUG_RETURN(-1); + } + else + DBUG_RETURN(nBytesWritten); +} + + +my_off_t my_win_lseek(File fd, my_off_t pos, int whence) +{ + LARGE_INTEGER offset; + LARGE_INTEGER newpos; + + DBUG_ENTER("my_win_lseek"); + + /* Check compatibility of Windows and Posix seek constants */ + compile_time_assert(FILE_BEGIN == SEEK_SET && FILE_CURRENT == SEEK_CUR + && FILE_END == SEEK_END); + + offset.QuadPart= pos; + if(!SetFilePointerEx(my_get_osfhandle(fd), offset, &newpos, whence)) + { + my_osmaperr(GetLastError()); + newpos.QuadPart= -1; + } + DBUG_RETURN(newpos.QuadPart); +} + + +#ifndef FILE_WRITE_TO_END_OF_FILE +#define FILE_WRITE_TO_END_OF_FILE 0xffffffff +#endif +size_t my_win_write(File fd, const uchar *Buffer, size_t Count) +{ + DWORD nWritten; + OVERLAPPED ov; + OVERLAPPED *pov= NULL; + HANDLE hFile; + + DBUG_ENTER("my_win_write"); + DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count %zd", fd, Buffer, Count)); + if(my_get_open_flags(fd) & _O_APPEND) + { + /* + Atomic append to the end of file is is done by special initialization of + the OVERLAPPED structure. See MSDN WriteFile documentation for more info. + */ + memset(&ov, 0, sizeof(ov)); + ov.Offset= FILE_WRITE_TO_END_OF_FILE; + ov.OffsetHigh= -1; + pov= &ov; + } + + hFile= my_get_osfhandle(fd); + if(!WriteFile(hFile, Buffer, (DWORD)Count, &nWritten, pov)) + { + nWritten= (size_t)-1; + my_osmaperr(GetLastError()); + } + DBUG_RETURN((size_t)nWritten); +} + + +int my_win_chsize(File fd, my_off_t newlength) +{ + HANDLE hFile; + LARGE_INTEGER length; + DBUG_ENTER("my_win_chsize"); + + hFile= (HANDLE) my_get_osfhandle(fd); + length.QuadPart= newlength; + if (!SetFilePointerEx(hFile, length , NULL , FILE_BEGIN)) + goto err; + if (!SetEndOfFile(hFile)) + goto err; + DBUG_RETURN(0); +err: + my_osmaperr(GetLastError()); + my_errno= errno; + DBUG_RETURN(-1); +} + + +/* Get the file descriptor for stdin,stdout or stderr */ +static File my_get_stdfile_descriptor(FILE *stream) +{ + HANDLE hFile; + DWORD nStdHandle; + DBUG_ENTER("my_get_stdfile_descriptor"); + + if(stream == stdin) + nStdHandle= STD_INPUT_HANDLE; + else if(stream == stdout) + nStdHandle= STD_OUTPUT_HANDLE; + else if(stream == stderr) + nStdHandle= STD_ERROR_HANDLE; + else + DBUG_RETURN(-1); + + hFile= GetStdHandle(nStdHandle); + if(hFile != INVALID_HANDLE_VALUE) + DBUG_RETURN(my_open_osfhandle(hFile, 0)); + DBUG_RETURN(-1); +} + + +File my_win_fileno(FILE *file) +{ + HANDLE hFile= (HANDLE)_get_osfhandle(fileno(file)); + int retval= -1; + uint i; + + DBUG_ENTER("my_win_fileno"); + + for(i= MY_FILE_MIN; i < my_file_limit; i++) + { + if(my_file_info[i].fhandle == hFile) + { + retval= i; + break; + } + } + if(retval == -1) + /* try std stream */ + DBUG_RETURN(my_get_stdfile_descriptor(file)); + DBUG_RETURN(retval); +} + + +FILE *my_win_fopen(const char *filename, const char *type) +{ + FILE *file; + int flags= 0; + DBUG_ENTER("my_win_open"); + + /* + If we are not creating, then we need to use my_access to make sure + the file exists since Windows doesn't handle files like "com1.sym" + very well + */ + if (check_if_legal_filename(filename)) + { + errno= EACCES; + DBUG_RETURN(NULL); + } + + file= fopen(filename, type); + if(!file) + DBUG_RETURN(NULL); + + if(strchr(type,'a') != NULL) + flags= O_APPEND; + + /* + Register file handle in my_table_info. + Necessary for my_fileno() + */ + if(my_open_osfhandle((HANDLE)_get_osfhandle(fileno(file)), flags) < 0) + { + fclose(file); + DBUG_RETURN(NULL); + } + DBUG_RETURN(file); +} + + +FILE * my_win_fdopen(File fd, const char *type) +{ + FILE *file; + int crt_fd; + int flags= 0; + + DBUG_ENTER("my_win_fdopen"); + + if(strchr(type,'a') != NULL) + flags= O_APPEND; + /* Convert OS file handle to CRT file descriptor and then call fdopen*/ + crt_fd= _open_osfhandle((intptr_t)my_get_osfhandle(fd), flags); + if(crt_fd < 0) + file= NULL; + else + file= fdopen(crt_fd, type); + DBUG_RETURN(file); +} + + +int my_win_fclose(FILE *file) +{ + File fd; + + DBUG_ENTER("my_win_close"); + fd= my_fileno(file); + if(fd < 0) + DBUG_RETURN(-1); + if(fclose(file) < 0) + DBUG_RETURN(-1); + invalidate_fd(fd); + DBUG_RETURN(0); +} + + + +/* + Quick and dirty my_fstat() implementation for Windows. + Use CRT fstat on temporarily allocated file descriptor. + Patch file size, because size that fstat returns is not + reliable (may be outdated) +*/ +int my_win_fstat(File fd, struct _stati64 *buf) +{ + int crt_fd; + int retval; + HANDLE hFile, hDup; + + DBUG_ENTER("my_win_fstat"); + + hFile= my_get_osfhandle(fd); + if(!DuplicateHandle( GetCurrentProcess(), hFile, GetCurrentProcess(), + &hDup ,0,FALSE,DUPLICATE_SAME_ACCESS)) + { + my_osmaperr(GetLastError()); + DBUG_RETURN(-1); + } + if ((crt_fd= _open_osfhandle((intptr_t)hDup,0)) < 0) + DBUG_RETURN(-1); + + retval= _fstati64(crt_fd, buf); + if(retval == 0) + { + /* File size returned by stat is not accurate (may be outdated), fix it*/ + GetFileSizeEx(hDup, (PLARGE_INTEGER) (&(buf->st_size))); + } + _close(crt_fd); + DBUG_RETURN(retval); +} + + + +int my_win_stat( const char *path, struct _stati64 *buf) +{ + DBUG_ENTER("my_win_stat"); + if(_stati64( path, buf) == 0) + { + /* File size returned by stat is not accurate (may be outdated), fix it*/ + WIN32_FILE_ATTRIBUTE_DATA data; + if (GetFileAttributesEx(path, GetFileExInfoStandard, &data)) + { + LARGE_INTEGER li; + li.LowPart= data.nFileSizeLow; + li.HighPart= data.nFileSizeHigh; + buf->st_size= li.QuadPart; + } + DBUG_RETURN(0); + } + DBUG_RETURN(-1); +} + + + +int my_win_fsync(File fd) +{ + DBUG_ENTER("my_win_fsync"); + if(FlushFileBuffers(my_get_osfhandle(fd))) + DBUG_RETURN(0); + my_osmaperr(GetLastError()); + DBUG_RETURN(-1); +} + + + +int my_win_dup(File fd) +{ + HANDLE hDup; + DBUG_ENTER("my_win_dup"); + if (DuplicateHandle(GetCurrentProcess(), my_get_osfhandle(fd), + GetCurrentProcess(), &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + DBUG_RETURN(my_open_osfhandle(hDup, my_get_open_flags(fd))); + } + my_osmaperr(GetLastError()); + DBUG_RETURN(-1); +} + +#endif /*_WIN32*/ diff --git a/mysys/my_write.c b/mysys/my_write.c index d7eb390bdd2..3eac1364f46 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -20,14 +20,14 @@ /* Write a chunk of bytes to a file */ -size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags) +size_t my_write(File Filedes, const uchar *Buffer, size_t Count, myf MyFlags) { - size_t writenbytes, written; + size_t writtenbytes, written; uint errors; DBUG_ENTER("my_write"); - DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d", - Filedes, (long) Buffer, (ulong) Count, MyFlags)); - errors=0; written=0; + DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %d", + Filedes, Buffer, (ulong) Count, MyFlags)); + errors= 0; written= 0; /* The behavior of write(fd, buf, 0) is not portable */ if (unlikely(!Count)) @@ -35,17 +35,22 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags) for (;;) { - if ((writenbytes= write(Filedes, Buffer, Count)) == Count) +#ifdef _WIN32 + writtenbytes= my_win_write(Filedes, Buffer, Count); +#else + writtenbytes= write(Filedes, Buffer, Count); +#endif + if (writtenbytes == Count) break; - if (writenbytes != (size_t) -1) + if (writtenbytes != (size_t) -1) { /* Safeguard */ - written+=writenbytes; - Buffer+=writenbytes; - Count-=writenbytes; + written+= writtenbytes; + Buffer+= writtenbytes; + Count-= writtenbytes; } - my_errno=errno; + my_errno= errno; DBUG_PRINT("error",("Write only %ld bytes, error: %d", - (long) writenbytes, my_errno)); + (long) writtenbytes, my_errno)); #ifndef NO_BACKGROUND #ifdef THREAD if (my_thread_var->abort) @@ -59,19 +64,19 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags) continue; } - if ((writenbytes == 0 || writenbytes == (size_t) -1)) + if ((writtenbytes == 0 || writtenbytes == (size_t) -1)) { if (my_errno == EINTR) { DBUG_PRINT("debug", ("my_write() was interrupted and returned %ld", - (long) writenbytes)); + (long) writtenbytes)); continue; /* Interrupted */ } - if (!writenbytes && !errors++) /* Retry once */ + if (!writtenbytes && !errors++) /* Retry once */ { /* We may come here if the file quota is exeeded */ - errno=EFBIG; /* Assume this is the error */ + errno= EFBIG; /* Assume this is the error */ continue; } } @@ -92,5 +97,5 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags) } if (MyFlags & (MY_NABP | MY_FNABP)) DBUG_RETURN(0); /* Want only errors */ - DBUG_RETURN(writenbytes+written); + DBUG_RETURN(writtenbytes+written); } /* my_write */ diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index 6e0959ae08c..4c4d6ea3598 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -42,3 +42,27 @@ extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time; #endif void my_error_unregister_all(void); + +#ifdef _WIN32 +/* my_winfile.c exports, should not be used outside mysys */ +extern File my_win_open(const char *path, int oflag); +extern int my_win_close(File fd); +extern size_t my_win_read(File fd, uchar *buffer, size_t count); +extern size_t my_win_write(File fd, const uchar *buffer, size_t count); +extern size_t my_win_pread(File fd, uchar *buffer, size_t count, + my_off_t offset); +extern size_t my_win_pwrite(File fd, const uchar *buffer, size_t count, + my_off_t offset); +extern my_off_t my_win_lseek(File fd, my_off_t pos, int whence); +extern int my_win_chsize(File fd, my_off_t newlength); +extern FILE* my_win_fopen(const char *filename, const char *type); +extern File my_win_fclose(FILE *file); +extern File my_win_fileno(FILE *file); +extern FILE* my_win_fdopen(File Filedes, const char *type); +extern int my_win_stat(const char *path, struct _stat64 *buf); +extern int my_win_fstat(File fd, struct _stat64 *buf); +extern int my_win_fsync(File fd); +extern File my_win_dup(File fd); +extern File my_win_sopen(const char *path, int oflag, int shflag, int perm); +extern File my_open_osfhandle(HANDLE handle, int oflag); +#endif diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 166c4f00158..0ad509ab43b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1135,7 +1135,29 @@ innobase_mysql_tmpfile(void) will be passed to fdopen(), it will be closed by invoking fclose(), which in turn will invoke close() instead of my_close(). */ + +#ifdef _WIN32 + /* Note that on Windows, the integer returned by mysql_tmpfile + has no relation to C runtime file descriptor. Here, we need + to call my_get_osfhandle to get the HANDLE and then convert it + to C runtime filedescriptor. */ + { + HANDLE hFile = my_get_osfhandle(fd); + HANDLE hDup; + BOOL bOK = + DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(), + &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS); + if(bOK) { + fd2 = _open_osfhandle((intptr_t)hDup,0); + } + else { + my_osmaperr(GetLastError()); + fd2 = -1; + } + } +#else fd2 = dup(fd); +#endif if (fd2 < 0) { DBUG_PRINT("error",("Got error %d on dup",fd2)); my_errno=errno; diff --git a/storage/myisam/mi_locking.c b/storage/myisam/mi_locking.c index 6a4c21160f4..8a5866ae763 100644 --- a/storage/myisam/mi_locking.c +++ b/storage/myisam/mi_locking.c @@ -236,7 +236,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) break; /* Impossible */ } } -#ifdef __WIN__ +#ifdef _WIN32 else { /* @@ -455,11 +455,11 @@ int _mi_writeinfo(register MI_INFO *info, uint operation) share->state.update_count= info->last_loop= ++info->this_loop; if ((error=mi_state_info_write(share->kfile, &share->state, 1))) olderror=my_errno; -#ifdef __WIN__ +#ifdef _WIN32 if (myisam_flush) { - _commit(share->kfile); - _commit(info->dfile); + my_sync(share->kfile,0); + my_sync(info->dfile,0); } #endif } From fc8db5e9ea231da4e8f5af3b38a12688d1590d53 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 11 Sep 2009 22:42:39 +0200 Subject: [PATCH 006/274] Downport WL#1624 -determine MAC addresses on Windows. Contribution by Chris Runyan --- mysys/my_gethwaddr.c | 92 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index c7f138c7337..7fae1a51446 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -101,7 +101,97 @@ err: return res; } -#else /* FreeBSD elif linux */ +#elif defined(__WIN__) +#include + +/* + The following typedef is for dynamically loading + iphlpapi.dll / GetAdaptersAddresses. Dynamic loading is + used because GetAdaptersAddresses is not available on Windows 2000 + which MySQL still supports. Static linking would cause an unresolved export. +*/ +typedef DWORD (WINAPI *pfnGetAdaptersAddresses)(IN ULONG Family, + IN DWORD Flags,IN PVOID Reserved, + OUT PIP_ADAPTER_ADDRESSES pAdapterAddresses, + IN OUT PULONG pOutBufLen); + +/* + my_gethwaddr - Windows version + + @brief Retrieve MAC address from network hardware + + @param[out] to MAC address exactly six bytes + + @return Operation status + @retval 0 OK + @retval <>0 FAILED +*/ +my_bool my_gethwaddr(uchar *to) +{ + PIP_ADAPTER_ADDRESSES pAdapterAddresses; + PIP_ADAPTER_ADDRESSES pCurrAddresses; + IP_ADAPTER_ADDRESSES adapterAddresses; + ULONG address_len; + my_bool return_val= 1; + static pfnGetAdaptersAddresses fnGetAdaptersAddresses= + (pfnGetAdaptersAddresses)-1; + + if(fnGetAdaptersAddresses == (pfnGetAdaptersAddresses)-1) + { + /* Get the function from the DLL */ + fnGetAdaptersAddresses= (pfnGetAdaptersAddresses) + GetProcAddress(LoadLibrary("iphlpapi.dll"), + "GetAdaptersAddresses"); + } + if (!fnGetAdaptersAddresses) + return 1; /* failed to get function */ + address_len= sizeof (IP_ADAPTER_ADDRESSES); + + /* Get the required size for the address data. */ + if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, &adapterAddresses, &address_len) + == ERROR_BUFFER_OVERFLOW) + { + pAdapterAddresses= my_malloc(address_len, 0); + if (!pAdapterAddresses) + return 1; /* error, alloc failed */ + } + else + pAdapterAddresses= &adapterAddresses; /* one is enough don't alloc */ + + /* Get the hardware info. */ + if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &address_len) + == NO_ERROR) + { + pCurrAddresses= pAdapterAddresses; + + while (pCurrAddresses) + { + /* Look for ethernet cards. */ + if (pCurrAddresses->IfType == IF_TYPE_ETHERNET_CSMACD) + { + /* check for a good address */ + if (pCurrAddresses->PhysicalAddressLength < 6) + continue; /* bad address */ + + /* save 6 bytes of the address in the 'to' parameter */ + memcpy(to, pCurrAddresses->PhysicalAddress, 6); + + /* Network card found, we're done. */ + return_val= 0; + break; + } + pCurrAddresses= pCurrAddresses->Next; + } + } + + /* Clean up memory allocation. */ + if (pAdapterAddresses != &adapterAddresses) + my_free(pAdapterAddresses, 0); + + return return_val; +} + +#else /* __FreeBSD__ || __linux__ || __WIN__ */ /* just fail */ my_bool my_gethwaddr(uchar *to __attribute__((unused))) { From 12cea944fc705b9b88d8750a61a2c8b3b53386f9 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 13 Sep 2009 19:38:06 +0200 Subject: [PATCH 007/274] fix compile error. definition of VOID in trunk still conflicts with windows headers. that was fixed in 6.0 --- mysys/my_gethwaddr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index 7fae1a51446..38fa0313c5d 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -102,6 +102,14 @@ err: } #elif defined(__WIN__) + +/* Workaround for BUG#32082 (Definition of VOID in my_global.h conflicts with +windows headers) */ +#ifdef VOID +#undef VOID +#define VOID void +#endif + #include /* From 6942c25e733967e4d3da8aaad3b2e9a2832dc33e Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 15 Sep 2009 17:07:52 +0200 Subject: [PATCH 008/274] WL#3352, Introducing Column list partitioning, makes it possible to partition on most data types, makes it possible to prune on multi-field partitioning --- BUILD/build_mccge.sh | 2 +- mysql-test/r/partition_mgm_err.result | 2 +- mysql-test/r/partition_range.result | 94 ++ .../suite/parts/inc/partition_key_32col.inc | 2 +- mysql-test/t/partition_column.test | 209 +++ mysql-test/t/partition_column_prune.test | 71 + mysql-test/t/partition_error.test | 6 +- mysql-test/t/partition_mgm_err.test | 2 +- mysql-test/t/partition_range.test | 76 + mysql-test/t/type_decimal.test | 10 +- sql/ha_partition.h | 3 +- sql/item_create.cc | 22 + sql/item_timefunc.cc | 33 + sql/item_timefunc.h | 18 + sql/lex.h | 1 + sql/opt_range.cc | 288 +++- sql/partition_element.h | 37 +- sql/partition_info.cc | 497 +++++-- sql/partition_info.h | 36 +- sql/share/errmsg.txt | 10 + sql/sql_lex.cc | 1 + sql/sql_lex.h | 3 + sql/sql_partition.cc | 1256 +++++++++++------ sql/sql_partition.h | 12 +- sql/sql_show.cc | 18 +- sql/sql_table.cc | 2 +- sql/sql_yacc.yy | 284 +++- 27 files changed, 2235 insertions(+), 760 deletions(-) create mode 100644 mysql-test/t/partition_column.test create mode 100644 mysql-test/t/partition_column_prune.test diff --git a/BUILD/build_mccge.sh b/BUILD/build_mccge.sh index ad3e728453c..379ca1b2c68 100755 --- a/BUILD/build_mccge.sh +++ b/BUILD/build_mccge.sh @@ -556,7 +556,7 @@ parse_package() package="pro" ;; extended ) - package="" + package="extended" ;; cge ) package="cge" diff --git a/mysql-test/r/partition_mgm_err.result b/mysql-test/r/partition_mgm_err.result index f8403988f47..a13278d724e 100644 --- a/mysql-test/r/partition_mgm_err.result +++ b/mysql-test/r/partition_mgm_err.result @@ -41,7 +41,7 @@ ERROR HY000: Reorganize of range partitions cannot change total ranges except fo ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO (PARTITION x01 VALUES LESS THAN (4), PARTITION x11 VALUES LESS THAN (2)); -ERROR HY000: Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range +ERROR HY000: VALUES LESS THAN value must be strictly increasing for each partition ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO (PARTITION x01 VALUES LESS THAN (6), PARTITION x11 VALUES LESS THAN (4)); diff --git a/mysql-test/r/partition_range.result b/mysql-test/r/partition_range.result index e8fc55b759b..fc15665d698 100644 --- a/mysql-test/r/partition_range.result +++ b/mysql-test/r/partition_range.result @@ -1,6 +1,100 @@ drop table if exists t1, t2; create table t1 (a int) partition by range (a) +( partition p0 values less than (NULL), +partition p1 values less than (MAXVALUE)); +ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '), +partition p1 values less than (MAXVALUE))' at line 3 +create table t1 (a datetime not null) +partition by range (TO_SECONDS(a)) +( partition p0 VALUES LESS THAN (TO_SECONDS('2007-03-08 00:00:00')), +partition p1 VALUES LESS THAN (TO_SECONDS('2007-04-01 00:00:00'))); +INSERT INTO t1 VALUES ('2007-03-01 12:00:00'), ('2007-03-07 12:00:00'); +INSERT INTO t1 VALUES ('2007-03-08 12:00:00'), ('2007-03-15 12:00:00'); +explain partitions select * from t1 where a < '2007-03-08 00:00:00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 2 Using where +explain partitions select * from t1 where a < '2007-03-08 00:00:01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a <= '2007-03-08 00:00:00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a <= '2007-03-07 23:59:59'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a < '2007-03-07 23:59:59'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 4 Using where +drop table t1; +create table t1 (a date) +partition by range(to_seconds(a)) +(partition p0 values less than (to_seconds('2004-01-01')), +partition p1 values less than (to_seconds('2005-01-01'))); +insert into t1 values ('2003-12-30'),('2004-12-31'); +select * from t1; +a +2003-12-30 +2004-12-31 +explain partitions select * from t1 where a <= '2003-12-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 system NULL NULL NULL NULL 1 +select * from t1 where a <= '2003-12-31'; +a +2003-12-30 +explain partitions select * from t1 where a <= '2005-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 2 Using where +select * from t1 where a <= '2005-01-01'; +a +2003-12-30 +2004-12-31 +drop table t1; +create table t1 (a datetime) +partition by range(to_seconds(a)) +(partition p0 values less than (to_seconds('2004-01-01 12:00:00')), +partition p1 values less than (to_seconds('2005-01-01 12:00:00'))); +insert into t1 values ('2004-01-01 11:59:29'),('2005-01-01 11:59:59'); +select * from t1; +a +2004-01-01 11:59:29 +2005-01-01 11:59:59 +explain partitions select * from t1 where a <= '2004-01-01 11:59.59'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 system NULL NULL NULL NULL 1 +select * from t1 where a <= '2004-01-01 11:59:59'; +a +2004-01-01 11:59:29 +explain partitions select * from t1 where a <= '2005-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 2 Using where +select * from t1 where a <= '2005-01-01'; +a +2004-01-01 11:59:29 +drop table t1; +create table t1 (a int, b char(20)) +partition by range column_list(a,b) +(partition p0 values less than (1)); +ERROR 42000: Inconsistency in usage of column lists for partitioning near '))' at line 3 +create table t1 (a int, b char(20)) +partition by range(a) +(partition p0 values less than (column_list(1,"b"))); +ERROR HY000: Inconsistency in usage of column lists for partitioning +create table t1 (a int, b char(20)) +partition by range(a) +(partition p0 values less than (column_list(1,"b"))); +ERROR HY000: Inconsistency in usage of column lists for partitioning +create table t1 (a int, b char(20)); +create global index inx on t1 (a,b) +partition by range (a) +(partition p0 values less than (1)); +drop table t1; +create table t1 (a int, b char(20)) +partition by range column_list(b) +(partition p0 values less than (column_list("b"))); +drop table t1; +create table t1 (a int) +partition by range (a) ( partition p0 values less than (maxvalue)); alter table t1 add partition (partition p1 values less than (100000)); ERROR HY000: MAXVALUE can only be used in last partition definition diff --git a/mysql-test/suite/parts/inc/partition_key_32col.inc b/mysql-test/suite/parts/inc/partition_key_32col.inc index 74016d9b556..b0635ca0e9c 100644 --- a/mysql-test/suite/parts/inc/partition_key_32col.inc +++ b/mysql-test/suite/parts/inc/partition_key_32col.inc @@ -1,4 +1,4 @@ ---error ER_TOO_MANY_KEY_PARTS +--error ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR eval create table t1 (a date not null, b varchar(50) not null, c varchar(50) not null, d enum('m', 'w') not null, e int not null, f decimal (18,2) not null, g bigint not null, h tinyint not null, a1 date not null, b1 varchar(50) not null, c1 varchar(50) not null, d1 enum('m', 'w') not null, e1 int not null, f1 decimal (18,2) not null, g1 bigint not null, h1 tinyint not null, a2 date not null, b2 varchar(50) not null, c2 varchar(50) not null, d2 enum('m', 'w') not null, e2 int not null, f2 decimal (18,2) not null, g2 bigint not null, h2 tinyint not null, a3 date not null, b3 varchar(50) not null, c3 varchar(50) not null, d3 enum('m', 'w') not null, e3 int not null, f3 decimal (18,2) not null, g3 bigint not null, h3 tinyint not null, i char(255), primary key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1,a2,b2,c2,d2,e2,f2,g2,h2,a3,b3,c3,d3,e3,f3,g3,h3)) engine=$engine partition by key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1,a2,b2,c2,d2,e2,f2,g2,h2,a3,b3,c3,d3,e3,f3,g3,h3) ( partition pa1 max_rows=20 min_rows=2, diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test new file mode 100644 index 00000000000..b1f5f4abfcf --- /dev/null +++ b/mysql-test/t/partition_column.test @@ -0,0 +1,209 @@ +# +# Tests for the new column list partitioning introduced in second +# version for partitioning. +# +--source include/have_partition.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int, b char(10), c varchar(25), d datetime) +partition by range column_list(a,b,c,d) +subpartition by hash (to_seconds(d)) +subpartitions 4 +( partition p0 values less than (column_list(1, NULL, MAXVALUE, NULL)), + partition p1 values less than (column_list(1, 'a', MAXVALUE, TO_DAYS('1999-01-01'))), + partition p2 values less than (column_list(1, 'a', MAXVALUE, MAXVALUE)), + partition p3 values less than (column_list(1, MAXVALUE, MAXVALUE, MAXVALUE))); +drop table t1; + +create table t1 (a int, b char(10), c varchar(5), d int) +partition by range column_list(a,b,c) +subpartition by key (c,d) +subpartitions 3 +( partition p0 values less than (column_list(1,'abc','abc')), + partition p1 values less than (column_list(2,'abc','abc')), + partition p2 values less than (column_list(3,'abc','abc')), + partition p3 values less than (column_list(4,'abc','abc'))); + +insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); +insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); +insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3); +insert into t1 values (1,'d','e',1),(2,'d','e',2),(3,'d','e',3); +select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) OR + (a = 1 AND b >= 'a' AND (c = 'c' OR (c = 'd' AND d = 2)))); +drop table t1; + +create table t1 (a int, b varchar(2), c int) +partition by range column_list (a, b, c) +(partition p0 values less than (column_list(1, 'A', 1)), + partition p1 values less than (column_list(1, 'B', 1))); +insert into t1 values (1, 'A', 1); +explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; +select * from t1 where a = 1 AND b <= 'A' and c = 1; +drop table t1; + +create table t1 (a char, b char, c char) +partition by list column_list(a) +( partition p0 values in (column_list('a'))); +insert into t1 (a) values ('a'); +select * from t1 where a = 'a'; +drop table t1; + +--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR +create table t1 (d timestamp) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), + partition p1 values less than (column_list('2040-01-01'))); + +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(null, 10))); +drop table t1; + +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), + partition p1 values less than (column_list('2009-01-01'))); +drop table t1; + +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('1999-01-01')), + partition p1 values less than (column_list('2000-01-01'))); +drop table t1; + +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), + partition p1 values less than (column_list('3000-01-01'))); +drop table t1; + +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p2 values less than (column_list(99,99)), + partition p1 values less than (column_list(99,999))); + +insert into t1 values (99,998); +select * from t1 where b = 998; +drop table t1; + +create table t1 as select to_seconds(null) as to_seconds; +select data_type from information_schema.columns +where column_name='to_seconds'; +drop table t1; + +--error ER_PARSE_ERROR +create table t1 (a int, b int) +partition by list column_list(a,b) +(partition p0 values in (column_list(maxvalue,maxvalue))); +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(maxvalue,maxvalue))); +drop table t1; + +create table t1 (a int) +partition by list column_list(a) +(partition p0 values in (column_list(0))); +select partition_method from information_schema.partitions where table_name='t1'; +drop table t1; + +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list('H23456')), + partition p1 values less than (column_list('M23456'))); +insert into t1 values ('F23456'); +select * from t1; +drop table t1; + +-- error 1054 +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list(H23456)), + partition p1 values less than (column_list(M23456))); + +-- error ER_RANGE_NOT_INCREASING_ERROR +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list(23456)), + partition p1 values less than (column_list(23456))); + +-- error 1064 +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (10)); + +-- error ER_PARTITION_COLUMN_LIST_ERROR +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(1,1,1)); + +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(1, NULL)), + partition p1 values less than (column_list(2, maxvalue)), + partition p2 values less than (column_list(3, 3)), + partition p3 values less than (column_list(10, NULL))); + +-- error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values (10,0); +insert into t1 values (0,1),(1,1),(2,1),(3,1),(3,4),(4,9),(9,1); +select * from t1; + +alter table t1 +partition by range column_list(b,a) +(partition p0 values less than (column_list(1,2)), + partition p1 values less than (column_list(3,3)), + partition p2 values less than (column_list(9,5))); +explain partitions select * from t1 where b < 2; +select * from t1 where b < 2; +explain partitions select * from t1 where b < 4; +select * from t1 where b < 4; + +alter table t1 reorganize partition p1 into +(partition p11 values less than (column_list(2,2)), + partition p12 values less than (column_list(3,3))); + +-- error ER_REORG_OUTSIDE_RANGE +alter table t1 reorganize partition p0 into +(partition p01 values less than (column_list(0,3)), + partition p02 values less than (column_list(1,1))); + +-- error ER_PARTITION_COLUMN_LIST_ERROR +alter table t1 reorganize partition p2 into +(partition p2 values less than(column_list(9,6,1))); + +-- error ER_PARTITION_COLUMN_LIST_ERROR +alter table t1 reorganize partition p2 into +(partition p2 values less than (10)); + +alter table t1 reorganize partition p2 into +(partition p21 values less than (column_list(4,7)), + partition p22 values less than (column_list(9,5))); +explain partitions select * from t1 where b < 4; +select * from t1 where b < 4; +drop table t1; + +#create table t1 (a int, b int) +#partition by range column_list(a,b) +#(partition p0 values less than (column_list(99,99)), +# partition p1 values less than (column_list(99,maxvalue))); +#drop table t1; + +create table t1 (a int, b int) +partition by list column_list(a,b) +subpartition by hash (b) +subpartitions 2 +(partition p0 values in (column_list(0,0), column_list(1,1)), + partition p1 values in (column_list(1000,1000))); +insert into t1 values (1000,1000); +#select * from t1 where a = 0 and b = 0; +drop table t1; + +create table t1 (a char, b char, c char) +partition by range column_list(a,b,c) +( partition p0 values less than (column_list('a','b','c'))); +alter table t1 add partition +(partition p1 values less than (column_list('b','c','d'))); +drop table t1; diff --git a/mysql-test/t/partition_column_prune.test b/mysql-test/t/partition_column_prune.test new file mode 100644 index 00000000000..52267a66b65 --- /dev/null +++ b/mysql-test/t/partition_column_prune.test @@ -0,0 +1,71 @@ +# +# Partition pruning tests for new COLUMN LIST feature +# +-- source include/have_partition.inc + +--disable_warnings +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +--enable_warnings + +create table t1 (a char, b char, c char) +partition by range column_list(a,b,c) +( partition p0 values less than (column_list('a','b','c'))); +insert into t1 values ('a', NULL, 'd'); +explain partitions select * from t1 where a = 'a' AND c = 'd'; +select * from t1 where a = 'a' AND c = 'd'; +drop table t1; + +## COLUMN_LIST partition pruning tests +create table t1 (a int not null) partition by range column_list(a) ( + partition p0 values less than (column_list(10)), + partition p1 values less than (column_list(20)), + partition p2 values less than (column_list(30)), + partition p3 values less than (column_list(40)), + partition p4 values less than (column_list(50)), + partition p5 values less than (column_list(60)), + partition p6 values less than (column_list(70)) +); +insert into t1 values (5),(15),(25),(35),(45),(55),(65); +insert into t1 values (5),(15),(25),(35),(45),(55),(65); + +create table t2 (a int not null) partition by range(a) ( + partition p0 values less than (10), + partition p1 values less than (20), + partition p2 values less than (30), + partition p3 values less than (40), + partition p4 values less than (50), + partition p5 values less than (60), + partition p6 values less than (70) +); +insert into t2 values (5),(15),(25),(35),(45),(55),(65); +insert into t2 values (5),(15),(25),(35),(45),(55),(65); + +explain partitions select * from t1 where a > 35 and a < 45; +explain partitions select * from t2 where a > 35 and a < 45; + +drop table t1, t2; + +create table t1 (a int not null, b int not null ) +partition by range column_list(a,b) ( + partition p01 values less than (column_list(2,10)), + partition p02 values less than (column_list(2,20)), + partition p03 values less than (column_list(2,30)), + + partition p11 values less than (column_list(4,10)), + partition p12 values less than (column_list(4,20)), + partition p13 values less than (column_list(4,30)), + + partition p21 values less than (column_list(6,10)), + partition p22 values less than (column_list(6,20)), + partition p23 values less than (column_list(6,30)) +); + +insert into t1 values (2,5), (2,15), (2,25), + (4,5), (4,15), (4,25), (6,5), (6,15), (6,25); +insert into t1 select * from t1; + +explain partitions select * from t1 where a=2; +explain partitions select * from t1 where a=4; +explain partitions select * from t1 where a=2 and b < 22; + +drop table t1; diff --git a/mysql-test/t/partition_error.test b/mysql-test/t/partition_error.test index 49632f95dfb..1e76945ca46 100644 --- a/mysql-test/t/partition_error.test +++ b/mysql-test/t/partition_error.test @@ -180,7 +180,7 @@ partitions 3 (partition x1, partition x2); # -# Partition by key specified 3 partitions but only defined 2 => error +# Partition by hash, random function # --error 1064 CREATE TABLE t1 ( @@ -193,7 +193,7 @@ partitions 2 (partition x1, partition x2); # -# Partition by key specified 3 partitions but only defined 2 => error +# Partition by range, random function # --error 1064 CREATE TABLE t1 ( @@ -206,7 +206,7 @@ partitions 2 (partition x1 values less than (0), partition x2 values less than (2)); # -# Partition by key specified 3 partitions but only defined 2 => error +# Partition by list, random function # --error 1064 CREATE TABLE t1 ( diff --git a/mysql-test/t/partition_mgm_err.test b/mysql-test/t/partition_mgm_err.test index 0f8b8d3cd90..f921fa8ebca 100644 --- a/mysql-test/t/partition_mgm_err.test +++ b/mysql-test/t/partition_mgm_err.test @@ -61,7 +61,7 @@ ALTER TABLE t1 REORGANIZE PARTITION x0, x1, x1 INTO ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO (PARTITION x01 VALUES LESS THAN (5)); ---error ER_REORG_OUTSIDE_RANGE +--error ER_RANGE_NOT_INCREASING_ERROR ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO (PARTITION x01 VALUES LESS THAN (4), PARTITION x11 VALUES LESS THAN (2)); diff --git a/mysql-test/t/partition_range.test b/mysql-test/t/partition_range.test index c02d9049f2e..c14dfd1822d 100644 --- a/mysql-test/t/partition_range.test +++ b/mysql-test/t/partition_range.test @@ -9,6 +9,82 @@ drop table if exists t1, t2; --enable_warnings +--error ER_PARSE_ERROR +create table t1 (a int) +partition by range (a) +( partition p0 values less than (NULL), + partition p1 values less than (MAXVALUE)); +# +# Merge fix of bug#27927 for TO_SECONDS function +# +create table t1 (a datetime not null) +partition by range (TO_SECONDS(a)) +( partition p0 VALUES LESS THAN (TO_SECONDS('2007-03-08 00:00:00')), + partition p1 VALUES LESS THAN (TO_SECONDS('2007-04-01 00:00:00'))); +INSERT INTO t1 VALUES ('2007-03-01 12:00:00'), ('2007-03-07 12:00:00'); +INSERT INTO t1 VALUES ('2007-03-08 12:00:00'), ('2007-03-15 12:00:00'); +explain partitions select * from t1 where a < '2007-03-08 00:00:00'; +explain partitions select * from t1 where a < '2007-03-08 00:00:01'; +explain partitions select * from t1 where a <= '2007-03-08 00:00:00'; +explain partitions select * from t1 where a <= '2007-03-07 23:59:59'; +explain partitions select * from t1 where a < '2007-03-07 23:59:59'; +drop table t1; +# +# New test cases for new function to_seconds +# +create table t1 (a date) +partition by range(to_seconds(a)) +(partition p0 values less than (to_seconds('2004-01-01')), + partition p1 values less than (to_seconds('2005-01-01'))); +insert into t1 values ('2003-12-30'),('2004-12-31'); +select * from t1; +explain partitions select * from t1 where a <= '2003-12-31'; +select * from t1 where a <= '2003-12-31'; +explain partitions select * from t1 where a <= '2005-01-01'; +select * from t1 where a <= '2005-01-01'; +drop table t1; + +create table t1 (a datetime) +partition by range(to_seconds(a)) +(partition p0 values less than (to_seconds('2004-01-01 12:00:00')), + partition p1 values less than (to_seconds('2005-01-01 12:00:00'))); +insert into t1 values ('2004-01-01 11:59:29'),('2005-01-01 11:59:59'); +select * from t1; +explain partitions select * from t1 where a <= '2004-01-01 11:59.59'; +select * from t1 where a <= '2004-01-01 11:59:59'; +explain partitions select * from t1 where a <= '2005-01-01'; +select * from t1 where a <= '2005-01-01'; +drop table t1; + +# +# Adding new test cases for column list variant for partitioning +# +--error 1064 +create table t1 (a int, b char(20)) +partition by range column_list(a,b) +(partition p0 values less than (1)); + +--error ER_PARTITION_COLUMN_LIST_ERROR +create table t1 (a int, b char(20)) +partition by range(a) +(partition p0 values less than (column_list(1,"b"))); + +--error ER_PARTITION_COLUMN_LIST_ERROR +create table t1 (a int, b char(20)) +partition by range(a) +(partition p0 values less than (column_list(1,"b"))); + +create table t1 (a int, b char(20)); +create global index inx on t1 (a,b) +partition by range (a) +(partition p0 values less than (1)); +drop table t1; + +create table t1 (a int, b char(20)) +partition by range column_list(b) +(partition p0 values less than (column_list("b"))); +drop table t1; + # # BUG 33429: Succeeds in adding partition when maxvalue on last partition # diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 8a81908296f..dfe36ed0905 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -8,13 +8,13 @@ SET SQL_WARNINGS=1; CREATE TABLE t1 ( id int(11) NOT NULL auto_increment, datatype_id int(11) DEFAULT '0' NOT NULL, - minvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL, - maxvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL, + min_value decimal(20,10) DEFAULT '0.0000000000' NOT NULL, + max_value decimal(20,10) DEFAULT '0.0000000000' NOT NULL, valuename varchar(20), forecolor int(11), backcolor int(11), PRIMARY KEY (id), - UNIQUE datatype_id (datatype_id, minvalue, maxvalue) + UNIQUE datatype_id (datatype_id, min_value, max_value) ); INSERT INTO t1 VALUES ( '1', '4', '0.0000000000', '0.0000000000', 'Ei saja', '0', '16776960'); INSERT INTO t1 VALUES ( '2', '4', '1.0000000000', '1.0000000000', 'Sajab', '16777215', '255'); @@ -148,8 +148,8 @@ INSERT INTO t1 VALUES ( '139', '21', '326.0000000000', '326.0000000000', 'Lumine INSERT INTO t1 VALUES ( '143', '16', '-4.9000000000', '-0.1000000000', '', NULL, '15774720'); INSERT INTO t1 VALUES ( '145', '15', '0.0000000000', '1.9000000000', '', '0', '16769024'); INSERT INTO t1 VALUES ( '146', '16', '0.0000000000', '1.9000000000', '', '0', '16769024'); -select * from t1 where minvalue<=1 and maxvalue>=-1 and datatype_id=16; -select * from t1 where minvalue<=-1 and maxvalue>=-1 and datatype_id=16; +select * from t1 where min_value<=1 and max_value>=-1 and datatype_id=16; +select * from t1 where min_value<=-1 and max_value>=-1 and datatype_id=16; drop table t1; # diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 8a81a759e2a..cc6558f2db0 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -19,7 +19,8 @@ enum partition_keywords { - PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR + PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR, + PKW_COLUMNS }; /* diff --git a/sql/item_create.cc b/sql/item_create.cc index bf359b10caa..3adc0112ff8 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -2052,6 +2052,18 @@ protected: virtual ~Create_func_to_days() {} }; +class Create_func_to_seconds : public Create_func_arg1 +{ +public: + virtual Item* create(THD *thd, Item *arg1); + + static Create_func_to_seconds s_singleton; + +protected: + Create_func_to_seconds() {} + virtual ~Create_func_to_seconds() {} +}; + #ifdef HAVE_SPATIAL class Create_func_touches : public Create_func_arg2 @@ -4480,6 +4492,15 @@ Create_func_to_days::create(THD *thd, Item *arg1) } +Create_func_to_seconds Create_func_to_seconds::s_singleton; + +Item* +Create_func_to_seconds::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_to_seconds(arg1); +} + + #ifdef HAVE_SPATIAL Create_func_touches Create_func_touches::s_singleton; @@ -4917,6 +4938,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("TIME_TO_SEC") }, BUILDER(Create_func_time_to_sec)}, { { C_STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)}, { { C_STRING_WITH_LEN("TO_DAYS") }, BUILDER(Create_func_to_days)}, + { { C_STRING_WITH_LEN("TO_SECONDS") }, BUILDER(Create_func_to_seconds)}, { { C_STRING_WITH_LEN("UCASE") }, BUILDER(Create_func_ucase)}, { { C_STRING_WITH_LEN("UNCOMPRESS") }, BUILDER(Create_func_uncompress)}, { { C_STRING_WITH_LEN("UNCOMPRESSED_LENGTH") }, BUILDER(Create_func_uncompressed_length)}, diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d79b0b02998..bad9b85b2b6 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -941,6 +941,27 @@ longlong Item_func_to_days::val_int() } +longlong Item_func_to_seconds::val_int_endpoint(bool left_endp, + bool *incl_endp) +{ + longlong res= val_int(); + return null_value ? LONGLONG_MIN : res; +} + +longlong Item_func_to_seconds::val_int() +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + longlong seconds; + longlong days; + if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) + return 0; + seconds=ltime.hour*3600L+ltime.minute*60+ltime.second; + seconds=ltime.neg ? -seconds : seconds; + days= (longlong) calc_daynr(ltime.year,ltime.month,ltime.day); + return (seconds + days * (24L * 3600L)); +} + /* Get information about this Item tree monotonicity @@ -967,6 +988,18 @@ enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const return NON_MONOTONIC; } +enum_monotonicity_info Item_func_to_seconds::get_monotonicity_info() const +{ + if (args[0]->type() == Item::FIELD_ITEM) + { + if (args[0]->field_type() == MYSQL_TYPE_DATE) + return MONOTONIC_STRICT_INCREASING; + if (args[0]->field_type() == MYSQL_TYPE_DATETIME) + return MONOTONIC_INCREASING; + } + return NON_MONOTONIC; +} + longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp) { diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 9e3c2e8c89f..fd42ec307db 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -73,6 +73,24 @@ public: }; +class Item_func_to_seconds :public Item_int_func +{ +public: + Item_func_to_seconds(Item *a) :Item_int_func(a) {} + longlong val_int(); + const char *func_name() const { return "to_seconds"; } + void fix_length_and_dec() + { + decimals=0; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; + maybe_null=1; + } + enum_monotonicity_info get_monotonicity_info() const; + longlong val_int_endpoint(bool left_endp, bool *incl_endp); + bool check_partition_func_processor(uchar *bool_arg) { return FALSE;} +}; + + class Item_func_dayofmonth :public Item_int_func { public: diff --git a/sql/lex.h b/sql/lex.h index 0a85824f6f7..c42ece86993 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -113,6 +113,7 @@ static SYMBOL symbols[] = { { "COLLATION", SYM(COLLATION_SYM)}, { "COLUMN", SYM(COLUMN_SYM)}, { "COLUMNS", SYM(COLUMNS)}, + { "COLUMN_LIST", SYM(COLUMN_LIST_SYM)}, { "COMMENT", SYM(COMMENT_SYM)}, { "COMMIT", SYM(COMMIT_SYM)}, { "COMMITTED", SYM(COMMITTED_SYM)}, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 47067c03a85..e226b51fc66 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -438,35 +438,55 @@ public: return 0; } - /* returns a number of keypart values appended to the key buffer */ - int store_min_key(KEY_PART *key, uchar **range_key, uint *range_key_flag) + /* + Returns a number of keypart values appended to the key buffer + for min key and max key. This function is used by both Range + Analysis and Partition pruning. For partition pruning we have + to ensure that we don't store also subpartition fields. Thus + we have to stop at the last partition part and not step into + the subpartition fields. For Range Analysis we set last_part + to MAX_KEY which we should never reach. + */ + int store_min_key(KEY_PART *key, + uchar **range_key, + uint *range_key_flag, + uint last_part) { SEL_ARG *key_tree= first(); uint res= key_tree->store_min(key[key_tree->part].store_length, range_key, *range_key_flag); *range_key_flag|= key_tree->min_flag; if (key_tree->next_key_part && + key_tree->part != last_part && key_tree->next_key_part->part == key_tree->part+1 && !(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) - res+= key_tree->next_key_part->store_min_key(key, range_key, - range_key_flag); + res+= key_tree->next_key_part->store_min_key(key, + range_key, + range_key_flag, + last_part); return res; } /* returns a number of keypart values appended to the key buffer */ - int store_max_key(KEY_PART *key, uchar **range_key, uint *range_key_flag) + int store_max_key(KEY_PART *key, + uchar **range_key, + uint *range_key_flag, + uint last_part) { SEL_ARG *key_tree= last(); uint res=key_tree->store_max(key[key_tree->part].store_length, range_key, *range_key_flag); (*range_key_flag)|= key_tree->max_flag; if (key_tree->next_key_part && + key_tree->part != last_part && key_tree->next_key_part->part == key_tree->part+1 && !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) - res+= key_tree->next_key_part->store_max_key(key, range_key, - range_key_flag); + res+= key_tree->next_key_part->store_max_key(key, + range_key, + range_key_flag, + last_part); return res; } @@ -634,6 +654,12 @@ public: using_real_indexes==TRUE */ uint real_keynr[MAX_KEY]; + + /* Used to store 'current key tuples', in both range analysis and + * partitioning (list) analysis*/ + uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], + max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; + /* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */ uint alloced_sel_args; }; @@ -645,8 +671,6 @@ public: longlong baseflag; uint max_key_part, range_count; - uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], - max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; bool quick; // Don't calulate possible keys uint fields_bitmap_size; @@ -2599,6 +2623,8 @@ typedef struct st_part_prune_param /* Same as above for subpartitioning */ my_bool *is_subpart_keypart; + my_bool ignore_part_fields; /* Ignore rest of partioning fields */ + /*************************************************************** Following fields form find_used_partitions() recursion context: **************************************************************/ @@ -2614,6 +2640,11 @@ typedef struct st_part_prune_param /* Initialized bitmap of no_subparts size */ MY_BITMAP subparts_bitmap; + + uchar *cur_min_key; + uchar *cur_max_key; + + uint cur_min_flag, cur_max_flag; } PART_PRUNE_PARAM; static bool create_partition_index_description(PART_PRUNE_PARAM *prune_par); @@ -2731,6 +2762,11 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond) prune_param.arg_stack_end= prune_param.arg_stack; prune_param.cur_part_fields= 0; prune_param.cur_subpart_fields= 0; + + prune_param.cur_min_key= prune_param.range_param.min_key; + prune_param.cur_max_key= prune_param.range_param.max_key; + prune_param.cur_min_flag= prune_param.cur_max_flag= 0; + init_all_partitions_iterator(part_info, &prune_param.part_iter); if (!tree->keys[0] || (-1 == (res= find_used_partitions(&prune_param, tree->keys[0])))) @@ -2967,6 +3003,11 @@ int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, SEL_IMERGE *imerge) ppar->arg_stack_end= ppar->arg_stack; ppar->cur_part_fields= 0; ppar->cur_subpart_fields= 0; + + ppar->cur_min_key= ppar->range_param.min_key; + ppar->cur_max_key= ppar->range_param.max_key; + ppar->cur_min_flag= ppar->cur_max_flag= 0; + init_all_partitions_iterator(ppar->part_info, &ppar->part_iter); SEL_ARG *key_tree= (*ptree)->keys[0]; if (!key_tree || (-1 == (res |= find_used_partitions(ppar, key_tree)))) @@ -3091,8 +3132,12 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) { int res, left_res=0, right_res=0; int partno= (int)key_tree->part; - bool pushed= FALSE; bool set_full_part_if_bad_ret= FALSE; + bool ignore_part_fields= ppar->ignore_part_fields; + bool did_set_ignore_part_fields= FALSE; + + if (check_stack_overrun(ppar->range_param.thd, 3*STACK_MIN_SIZE, NULL)) + return -1; if (key_tree->left != &null_element) { @@ -3100,35 +3145,153 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) return -1; } + /* Push SEL_ARG's to stack to enable looking backwards as well */ + ppar->cur_part_fields+= ppar->is_part_keypart[partno]; + ppar->cur_subpart_fields+= ppar->is_subpart_keypart[partno]; + *(ppar->arg_stack_end++)= key_tree; + if (key_tree->type == SEL_ARG::KEY_RANGE) { - if (partno == 0 && (NULL != ppar->part_info->get_part_iter_for_interval)) + if (ppar->part_info->get_part_iter_for_interval && + key_tree->part <= ppar->last_part_partno) { - /* - Partitioning is done by RANGE|INTERVAL(monotonic_expr(fieldX)), and - we got "const1 CMP fieldX CMP const2" interval <-- psergey-todo: change + if (ignore_part_fields) + { + /* + We come here when a condition on the first partitioning + fields led to evaluating the partitioning condition + (due to finding a condition of the type a < const or + b > const). Thus we must ignore the rest of the + partitioning fields but we still want to analyse the + subpartitioning fields. + */ + if (key_tree->next_key_part) + res= find_used_partitions(ppar, key_tree->next_key_part); + else + res= -1; + goto pop_and_go_right; + } + /* Collect left and right bound, their lengths and flags */ + uchar *min_key= ppar->cur_min_key; + uchar *max_key= ppar->cur_max_key; + uchar *tmp_min_key= min_key; + uchar *tmp_max_key= max_key; + key_tree->store_min(ppar->key[key_tree->part].store_length, + &tmp_min_key, ppar->cur_min_flag); + key_tree->store_max(ppar->key[key_tree->part].store_length, + &tmp_max_key, ppar->cur_max_flag); + uint flag; + if (key_tree->next_key_part && + key_tree->next_key_part->part == key_tree->part+1 && + key_tree->next_key_part->part <= ppar->last_part_partno && + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + { + /* + There are more key parts for partition pruning to handle + This mainly happens when the condition is an equality + condition. + */ + if ((tmp_min_key - min_key) == (tmp_max_key - max_key) && + (memcmp(min_key, max_key, (uint)(tmp_max_key - max_key)) == 0) && + !key_tree->min_flag && !key_tree->max_flag) + { + /* Set 'parameters' */ + ppar->cur_min_key= tmp_min_key; + ppar->cur_max_key= tmp_max_key; + uint save_min_flag= ppar->cur_min_flag; + uint save_max_flag= ppar->cur_max_flag; + + ppar->cur_min_flag|= key_tree->min_flag; + ppar->cur_max_flag|= key_tree->max_flag; + + res= find_used_partitions(ppar, key_tree->next_key_part); + + /* Restore 'parameters' back */ + ppar->cur_min_key= min_key; + ppar->cur_max_key= max_key; + + ppar->cur_min_flag= save_min_flag; + ppar->cur_max_flag= save_max_flag; + goto pop_and_go_right; + } + /* We have arrived at the last field in the partition pruning */ + uint tmp_min_flag= key_tree->min_flag, + tmp_max_flag= key_tree->max_flag; + if (!tmp_min_flag) + key_tree->next_key_part->store_min_key(ppar->key, + &tmp_min_key, + &tmp_min_flag, + ppar->last_part_partno); + if (!tmp_max_flag) + key_tree->next_key_part->store_max_key(ppar->key, + &tmp_max_key, + &tmp_max_flag, + ppar->last_part_partno); + flag= tmp_min_flag | tmp_max_flag; + } + else + flag= key_tree->min_flag | key_tree->max_flag; + + if (tmp_min_key != ppar->range_param.min_key) + flag&= ~NO_MIN_RANGE; + else + flag|= NO_MIN_RANGE; + if (tmp_max_key != ppar->range_param.max_key) + flag&= ~NO_MAX_RANGE; + else + flag|= NO_MAX_RANGE; + + /* + We need to call the interval mapper if we have a condition which + makes sense to prune on. In the example of a COLUMN_LIST on a and + b it makes sense if we have a condition on a, or conditions on + both a and b. If we only have conditions on b it might make sense + but this is a harder case we will solve later. For the harder case + this clause then turns into use of all partitions and thus we + simply set res= -1 as if the mapper had returned that. */ - DBUG_EXECUTE("info", dbug_print_segment_range(key_tree, - ppar->range_param. - key_parts);); - res= ppar->part_info-> - get_part_iter_for_interval(ppar->part_info, - FALSE, - key_tree->min_value, - key_tree->max_value, - key_tree->min_flag | key_tree->max_flag, - &ppar->part_iter); - if (!res) - goto go_right; /* res==0 --> no satisfying partitions */ + if (ppar->arg_stack[0]->part == 0) + { + uint32 i; + uint32 store_length_array[MAX_KEY]; + uint32 num_keys= ppar->part_fields; + + for (i= 0; i < num_keys; i++) + store_length_array[i]= ppar->key[i].store_length; + res= ppar->part_info-> + get_part_iter_for_interval(ppar->part_info, + FALSE, + store_length_array, + ppar->range_param.min_key, + ppar->range_param.max_key, + tmp_min_key - ppar->range_param.min_key, + tmp_max_key - ppar->range_param.max_key, + flag, + &ppar->part_iter); + if (!res) + goto pop_and_go_right; /* res==0 --> no satisfying partitions */ + } + else + res= -1; + if (res == -1) { - //get a full range iterator + /* get a full range iterator */ init_all_partitions_iterator(ppar->part_info, &ppar->part_iter); } /* Save our intent to mark full partition as used if we will not be able to obtain further limits on subpartitions */ + if (partno < ppar->last_part_partno) + { + /* + We need to ignore the rest of the partitioning fields in all + evaluations after this + */ + did_set_ignore_part_fields= TRUE; + ppar->ignore_part_fields= TRUE; + } set_full_part_if_bad_ret= TRUE; goto process_next_key_part; } @@ -3143,13 +3306,16 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) res= ppar->part_info-> get_subpart_iter_for_interval(ppar->part_info, TRUE, + NULL, /* Currently not used here */ key_tree->min_value, key_tree->max_value, - key_tree->min_flag | key_tree->max_flag, + 0, 0, /* Those are ignored here */ + key_tree->min_flag | + key_tree->max_flag, &subpart_iter); DBUG_ASSERT(res); /* We can't get "no satisfying subpartitions" */ if (res == -1) - return -1; /* all subpartitions satisfy */ + goto pop_and_go_right; /* all subpartitions satisfy */ uint32 subpart_id; bitmap_clear_all(&ppar->subparts_bitmap); @@ -3167,18 +3333,14 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) bitmap_set_bit(&ppar->part_info->used_partitions, part_id * ppar->part_info->no_subparts + i); } - goto go_right; + goto pop_and_go_right; } if (key_tree->is_singlepoint()) { - pushed= TRUE; - ppar->cur_part_fields+= ppar->is_part_keypart[partno]; - ppar->cur_subpart_fields+= ppar->is_subpart_keypart[partno]; - *(ppar->arg_stack_end++) = key_tree; - if (partno == ppar->last_part_partno && - ppar->cur_part_fields == ppar->part_fields) + ppar->cur_part_fields == ppar->part_fields && + ppar->part_info->get_part_iter_for_interval == NULL) { /* Ok, we've got "fieldN<=>constN"-type SEL_ARGs for all partitioning @@ -3245,7 +3407,10 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) able to infer any suitable condition, so bail out. */ if (partno >= ppar->last_part_partno) - return -1; + { + res= -1; + goto pop_and_go_right; + } } } @@ -3254,7 +3419,17 @@ process_next_key_part: res= find_used_partitions(ppar, key_tree->next_key_part); else res= -1; - + + if (did_set_ignore_part_fields) + { + /* + We have returned from processing all key trees linked to our next + key part. We are ready to be moving down (using right pointers) and + this tree is a new evaluation requiring its own decision on whether + to ignore partitioning fields. + */ + ppar->ignore_part_fields= FALSE; + } if (set_full_part_if_bad_ret) { if (res == -1) @@ -3277,18 +3452,14 @@ process_next_key_part: init_all_partitions_iterator(ppar->part_info, &ppar->part_iter); } - if (pushed) - { pop_and_go_right: - /* Pop this key part info off the "stack" */ - ppar->arg_stack_end--; - ppar->cur_part_fields-= ppar->is_part_keypart[partno]; - ppar->cur_subpart_fields-= ppar->is_subpart_keypart[partno]; - } + /* Pop this key part info off the "stack" */ + ppar->arg_stack_end--; + ppar->cur_part_fields-= ppar->is_part_keypart[partno]; + ppar->cur_subpart_fields-= ppar->is_subpart_keypart[partno]; if (res == -1) return -1; -go_right: if (key_tree->right != &null_element) { if (-1 == (right_res= find_used_partitions(ppar,key_tree->right))) @@ -3377,6 +3548,7 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) uint total_parts= used_part_fields + used_subpart_fields; + ppar->ignore_part_fields= FALSE; ppar->part_fields= used_part_fields; ppar->last_part_partno= (int)used_part_fields - 1; @@ -7477,12 +7649,16 @@ check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree, tmp_max_flag=key_tree->max_flag; if (!tmp_min_flag) tmp_min_keypart+= - key_tree->next_key_part->store_min_key(param->key[idx], &tmp_min_key, - &tmp_min_flag); + key_tree->next_key_part->store_min_key(param->key[idx], + &tmp_min_key, + &tmp_min_flag, + MAX_KEY); if (!tmp_max_flag) tmp_max_keypart+= - key_tree->next_key_part->store_max_key(param->key[idx], &tmp_max_key, - &tmp_max_flag); + key_tree->next_key_part->store_max_key(param->key[idx], + &tmp_max_key, + &tmp_max_flag, + MAX_KEY); min_key_length= (uint) (tmp_min_key - param->min_key); max_key_length= (uint) (tmp_max_key - param->max_key); } @@ -7752,11 +7928,15 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, { uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag; if (!tmp_min_flag) - min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key, - &tmp_min_flag); + min_part+= key_tree->next_key_part->store_min_key(key, + &tmp_min_key, + &tmp_min_flag, + MAX_KEY); if (!tmp_max_flag) - max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key, - &tmp_max_flag); + max_part+= key_tree->next_key_part->store_max_key(key, + &tmp_max_key, + &tmp_max_flag, + MAX_KEY); flag=tmp_min_flag | tmp_max_flag; } } diff --git a/sql/partition_element.h b/sql/partition_element.h index 905bc38165b..d749681fe9b 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 MySQL AB +/* Copyright (C) 2006-2009 MySQL AB 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 @@ -35,6 +35,35 @@ enum partition_state { PART_IS_ADDED= 8 }; +/* + This struct is used to keep track of column expressions as part + of the COLUMNS concept in conjunction with RANGE and LIST partitioning. + The value can be either of MINVALUE, MAXVALUE and an expression that + must be constant and evaluate to the same type as the column it + represents. + + The data in this fixed in two steps. The parser will only fill in whether + it is a max_value or provide an expression. Filling in + column_value, part_info, partition_id, null_value is done by the + function fix_column_value_function. However the item tree needs + fixed also before writing it into the frm file (in add_column_list_values). + To distinguish between those two variants, fixed= 1 after the + fixing in add_column_list_values and fixed= 2 otherwise. This is + since the fixing in add_column_list_values isn't a complete fixing. +*/ + +typedef struct p_column_list_val +{ + void* column_value; + Item* item_expression; + partition_info *part_info; + uint partition_id; + bool max_value; + bool null_value; + char fixed; +} part_column_list_val; + + /* This struct is used to contain the value of an element in the VALUES IN struct. It needs to keep knowledge of @@ -47,6 +76,7 @@ typedef struct p_elem_val longlong value; bool null_value; bool unsigned_flag; + part_column_list_val *col_val_array; } part_elem_value; struct st_ddl_log_memory_entry; @@ -68,8 +98,9 @@ public: enum partition_state part_state; uint16 nodegroup_id; bool has_null_value; - bool signed_flag;/* Indicate whether this partition uses signed constants */ - bool max_value; /* Indicate whether this partition uses MAXVALUE */ + /* signed_flag and max_value only relevant for subpartitions */ + bool signed_flag; + bool max_value; partition_element() : part_max_rows(0), part_min_rows(0), range_value(0), diff --git a/sql/partition_info.cc b/sql/partition_info.cc index e2027d3571e..bb7c7c2be0f 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -591,6 +591,7 @@ error: SYNOPSIS check_range_constants() + thd Thread object RETURN VALUE TRUE An error occurred during creation of range constants @@ -603,76 +604,112 @@ error: called for RANGE PARTITIONed tables. */ -bool partition_info::check_range_constants() +bool partition_info::check_range_constants(THD *thd) { partition_element* part_def; - longlong current_largest; - longlong part_range_value; bool first= TRUE; uint i; List_iterator it(partitions); - bool result= TRUE; - bool signed_flag= !part_expr->unsigned_flag; + int result= TRUE; DBUG_ENTER("partition_info::check_range_constants"); - DBUG_PRINT("enter", ("INT_RESULT with %d parts", no_parts)); + DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", no_parts, + column_list)); - LINT_INIT(current_largest); - - part_result_type= INT_RESULT; - range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong)); - if (unlikely(range_int_array == NULL)) + if (column_list) { - mem_alloc_error(no_parts * sizeof(longlong)); - goto end; - } - i= 0; - do - { - part_def= it++; - if ((i != (no_parts - 1)) || !defined_max_value) + part_column_list_val* loc_range_col_array; + part_column_list_val *current_largest_col_val; + uint no_column_values= part_field_list.elements; + uint size_entries= sizeof(part_column_list_val) * no_column_values; + range_col_array= (part_column_list_val*)sql_calloc(no_parts * + size_entries); + LINT_INIT(current_largest_col_val); + if (unlikely(range_col_array == NULL)) { - part_range_value= part_def->range_value; - if (!signed_flag) - part_range_value-= 0x8000000000000000ULL; + mem_alloc_error(no_parts * sizeof(longlong)); + goto end; } - else - part_range_value= LONGLONG_MAX; - if (first) + loc_range_col_array= range_col_array; + i= 0; + do { - current_largest= part_range_value; - range_int_array[0]= part_range_value; - first= FALSE; - } - else - { - if (likely(current_largest < part_range_value)) + part_def= it++; { - current_largest= part_range_value; - range_int_array[i]= part_range_value; + List_iterator list_val_it(part_def->list_val_list); + part_elem_value *range_val= list_val_it++; + part_column_list_val *col_val= range_val->col_val_array; + + if (fix_column_value_functions(thd, col_val, i)) + goto end; + memcpy(loc_range_col_array, (const void*)col_val, size_entries); + loc_range_col_array+= no_column_values; + if (!first) + { + if (compare_column_values((const void*)current_largest_col_val, + (const void*)col_val) >= 0) + goto range_not_increasing_error; + } + current_largest_col_val= col_val; } - else if (defined_max_value && - current_largest == part_range_value && - part_range_value == LONGLONG_MAX && - i == (no_parts - 1)) + first= FALSE; + } while (++i < no_parts); + } + else + { + longlong current_largest; + longlong part_range_value; + bool signed_flag= !part_expr->unsigned_flag; + + LINT_INIT(current_largest); + + part_result_type= INT_RESULT; + range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong)); + if (unlikely(range_int_array == NULL)) + { + mem_alloc_error(no_parts * sizeof(longlong)); + goto end; + } + i= 0; + do + { + part_def= it++; + if ((i != (no_parts - 1)) || !defined_max_value) { - range_int_array[i]= part_range_value; + part_range_value= part_def->range_value; + if (!signed_flag) + part_range_value-= 0x8000000000000000ULL; } else + part_range_value= LONGLONG_MAX; + + if (!first) { - my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0)); - goto end; + if (unlikely(current_largest > part_range_value) || + (unlikely(current_largest == part_range_value) && + (part_range_value < LONGLONG_MAX || + i != (no_parts - 1) || + !defined_max_value))) + goto range_not_increasing_error; } - } - } while (++i < no_parts); + range_int_array[i]= part_range_value; + current_largest= part_range_value; + first= FALSE; + } while (++i < no_parts); + } result= FALSE; end: DBUG_RETURN(result); + +range_not_increasing_error: + my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0)); + goto end; } /* Support routines for check_list_constants used by qsort to sort the - constant list expressions. One routine for unsigned and one for signed. + constant list expressions. One routine for integers and one for + column lists. SYNOPSIS list_part_cmp() @@ -697,6 +734,133 @@ int partition_info::list_part_cmp(const void* a, const void* b) return 0; } + /* + Compare two lists of column values in RANGE/LIST partitioning + SYNOPSIS + compare_column_values() + first First column list argument + second Second column list argument + RETURN VALUES + 0 Equal + -1 First argument is smaller + +1 First argument is larger +*/ + +int partition_info::compare_column_values(const void *first_arg, + const void *second_arg) +{ + const part_column_list_val *first= (part_column_list_val*)first_arg; + const part_column_list_val *second= (part_column_list_val*)second_arg; + partition_info *part_info= first->part_info; + Field **field; + + for (field= part_info->part_field_array; *field; + field++, first++, second++) + { + if (first->max_value || second->max_value) + { + if (first->max_value && second->max_value) + continue; + if (second->max_value) + return -1; + else + return +1; + } + if (first->null_value || second->null_value) + { + if (first->null_value && second->null_value) + continue; + if (second->null_value) + return +1; + else + return -1; + } + int res= (*field)->cmp((const uchar*)first->column_value, + (const uchar*)second->column_value); + if (res) + return res; + } + return 0; +} + +/* + Evaluate VALUES functions for column list values + SYNOPSIS + fix_column_value_functions() + thd Thread object + col_val List of column values + part_id Partition id we are fixing + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Fix column VALUES and store in memory array adapted to the data type +*/ + +bool partition_info::fix_column_value_functions(THD *thd, + part_column_list_val *col_val, + uint part_id) +{ + uint no_columns= part_field_list.elements; + Name_resolution_context *context= &thd->lex->current_select->context; + TABLE_LIST *save_list= context->table_list; + bool result= FALSE; + uint i; + const char *save_where= thd->where; + DBUG_ENTER("partition_info::fix_column_value_functions"); + if (col_val->fixed > 1) + { + DBUG_RETURN(FALSE); + } + context->table_list= 0; + thd->where= "partition function"; + for (i= 0; i < no_columns; col_val++, i++) + { + Item *column_item= col_val->item_expression; + Field *field= part_field_array[i]; + col_val->part_info= this; + col_val->partition_id= part_id; + if (col_val->max_value) + col_val->column_value= NULL; + else + { + if (!col_val->fixed && + (column_item->fix_fields(thd, (Item**)0) || + (!column_item->const_item()))) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + result= TRUE; + goto end; + } + col_val->null_value= column_item->null_value; + col_val->column_value= NULL; + if (!col_val->null_value) + { + uchar *val_ptr; + uint len= field->pack_length(); + if (column_item->save_in_field(field, TRUE)) + { + my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); + result= TRUE; + goto end; + } + if (!(val_ptr= (uchar*) sql_calloc(len))) + { + mem_alloc_error(len); + result= TRUE; + goto end; + } + col_val->column_value= val_ptr; + memcpy(val_ptr, field->ptr, len); + } + } + col_val->fixed= 2; + } +end: + thd->where= save_where; + context->table_list= save_list; + DBUG_RETURN(result); +} /* This routine allocates an array for all list constants to achieve a fast @@ -706,6 +870,7 @@ int partition_info::list_part_cmp(const void* a, const void* b) SYNOPSIS check_list_constants() + thd Thread object RETURN VALUE TRUE An error occurred during creation of list constants @@ -718,15 +883,18 @@ int partition_info::list_part_cmp(const void* a, const void* b) called for LIST PARTITIONed tables. */ -bool partition_info::check_list_constants() +bool partition_info::check_list_constants(THD *thd) { - uint i; + uint i, size_entries, no_column_values; uint list_index= 0; part_elem_value *list_value; bool result= TRUE; - longlong curr_value, prev_value, type_add, calc_value; + longlong type_add, calc_value; + void *curr_value, *prev_value; partition_element* part_def; bool found_null= FALSE; + int (*compare_func)(const void *, const void*); + void *ptr; List_iterator list_func_it(partitions); DBUG_ENTER("partition_info::check_list_constants"); @@ -767,48 +935,86 @@ bool partition_info::check_list_constants() no_list_values++; } while (++i < no_parts); list_func_it.rewind(); - list_array= (LIST_PART_ENTRY*)sql_alloc((no_list_values+1) * - sizeof(LIST_PART_ENTRY)); - if (unlikely(list_array == NULL)) + no_column_values= part_field_list.elements; + size_entries= column_list ? + (no_column_values * sizeof(part_column_list_val)) : + sizeof(LIST_PART_ENTRY); + ptr= sql_calloc((no_list_values+1) * size_entries); + if (unlikely(ptr == NULL)) { - mem_alloc_error(no_list_values * sizeof(LIST_PART_ENTRY)); + mem_alloc_error(no_list_values * size_entries); goto end; } - - i= 0; - /* - Fix to be able to reuse signed sort functions also for unsigned - partition functions. - */ - type_add= (longlong)(part_expr->unsigned_flag ? + if (column_list) + { + part_column_list_val *loc_list_col_array; + loc_list_col_array= (part_column_list_val*)ptr; + list_col_array= (part_column_list_val*)ptr; + compare_func= compare_column_values; + i= 0; + /* + Fix to be able to reuse signed sort functions also for unsigned + partition functions. + */ + do + { + part_def= list_func_it++; + List_iterator list_val_it2(part_def->list_val_list); + while ((list_value= list_val_it2++)) + { + part_column_list_val *col_val= list_value->col_val_array; + if (unlikely(fix_column_value_functions(thd, col_val, i))) + { + DBUG_RETURN(TRUE); + } + memcpy(loc_list_col_array, (const void*)col_val, size_entries); + loc_list_col_array+= no_column_values; + } + } while (++i < no_parts); + } + else + { + compare_func= list_part_cmp; + list_array= (LIST_PART_ENTRY*)ptr; + i= 0; + /* + Fix to be able to reuse signed sort functions also for unsigned + partition functions. + */ + type_add= (longlong)(part_expr->unsigned_flag ? 0x8000000000000000ULL : 0ULL); - do - { - part_def= list_func_it++; - List_iterator list_val_it2(part_def->list_val_list); - while ((list_value= list_val_it2++)) + do { - calc_value= list_value->value - type_add; - list_array[list_index].list_value= calc_value; - list_array[list_index++].partition_id= i; - } - } while (++i < no_parts); - + part_def= list_func_it++; + List_iterator list_val_it2(part_def->list_val_list); + while ((list_value= list_val_it2++)) + { + calc_value= list_value->value - type_add; + list_array[list_index].list_value= calc_value; + list_array[list_index++].partition_id= i; + } + } while (++i < no_parts); + } if (fixed && no_list_values) { bool first= TRUE; + /* + list_array and list_col_array are unions, so this works for both + variants of LIST partitioning. + */ my_qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), &list_part_cmp); - + i= 0; LINT_INIT(prev_value); do { DBUG_ASSERT(i < no_list_values); - curr_value= list_array[i].list_value; - if (likely(first || prev_value != curr_value)) + curr_value= column_list ? (void*)&list_col_array[no_column_values * i] : + (void*)&list_array[i]; + if (likely(first || compare_func(curr_value, prev_value))) { prev_value= curr_value; first= FALSE; @@ -831,10 +1037,11 @@ end: SYNOPSIS check_partition_info() + thd Thread object + eng_type Return value for used engine in partitions file A reference to a handler of the table info Create info - engine_type Return value for used engine in partitions - check_partition_function Should we check the partition function + add_or_reorg_part Is it ALTER TABLE ADD/REORGANIZE command RETURN VALUE TRUE Error, something went wrong @@ -850,7 +1057,7 @@ end: bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, handler *file, HA_CREATE_INFO *info, - bool check_partition_function) + bool add_or_reorg_part) { handlerton *table_engine= default_engine_type; uint i, tot_partitions; @@ -861,11 +1068,11 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, DBUG_PRINT("info", ("default table_engine = %s", ha_resolve_storage_engine_name(table_engine))); - if (check_partition_function) + if (!add_or_reorg_part) { int err= 0; - if (part_type != HASH_PARTITION || !list_of_part_fields) + if (!list_of_part_fields) { DBUG_ASSERT(part_expr); err= part_expr->walk(&Item::check_partition_func_processor, 0, @@ -1064,10 +1271,12 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, list constants. */ - if (fixed) + if (add_or_reorg_part) { - if (unlikely((part_type == RANGE_PARTITION && check_range_constants()) || - (part_type == LIST_PARTITION && check_list_constants()))) + if (unlikely((part_type == RANGE_PARTITION && + check_range_constants(thd)) || + (part_type == LIST_PARTITION && + check_list_constants(thd)))) goto end; } result= FALSE; @@ -1098,20 +1307,96 @@ void partition_info::print_no_partition_found(TABLE *table) if (check_single_table_access(current_thd, SELECT_ACL, &table_list, TRUE)) + { my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE, ER(ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), MYF(0)); + } else { - my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); - if (part_expr->null_value) - buf_ptr= (char*)"NULL"; + if (column_list) + buf_ptr= (char*)"from column_list"; else - longlong2str(err_value, buf, - part_expr->unsigned_flag ? 10 : -10); + { + my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); + if (part_expr->null_value) + buf_ptr= (char*)"NULL"; + else + longlong2str(err_value, buf, + part_expr->unsigned_flag ? 10 : -10); + dbug_tmp_restore_column_map(table->read_set, old_map); + } my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr); - dbug_tmp_restore_column_map(table->read_set, old_map); } } + + +/* + Create a new column value in current list + SYNOPSIS + add_column_value() + RETURN + >0 A part_column_list_val object which have been + inserted into its list + 0 Memory allocation failure +*/ + +part_column_list_val *partition_info::add_column_value() +{ + uint max_val= num_columns ? num_columns : MAX_REF_PARTS; + DBUG_ENTER("add_column_value"); + DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u", + num_columns, curr_list_object, max_val)); + if (curr_list_object < max_val) + { + DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]); + } + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(NULL); +} + + +/* + Set fields related to partition expression + SYNOPSIS + set_part_expr() + start_token Start of partition function string + item_ptr Pointer to item tree + end_token End of partition function string + is_subpart Subpartition indicator + RETURN VALUES + TRUE Memory allocation error + FALSE Success +*/ + +bool partition_info::set_part_expr(char *start_token, Item *item_ptr, + char *end_token, bool is_subpart) +{ + uint expr_len= end_token - start_token; + char *func_string= (char*) sql_memdup(start_token, expr_len); + + if (!func_string) + { + mem_alloc_error(expr_len); + return TRUE; + } + if (is_subpart) + { + list_of_subpart_fields= FALSE; + subpart_expr= item_ptr; + subpart_func_string= func_string; + subpart_func_len= expr_len; + } + else + { + list_of_part_fields= FALSE; + part_expr= item_ptr; + part_func_string= func_string; + part_func_len= expr_len; + } + return FALSE; +} + + /* Set up buffers and arrays for fields requiring preparation SYNOPSIS @@ -1223,46 +1508,6 @@ bool partition_info::set_up_charset_field_preps() } subpart_charset_field_array[i]= NULL; } - if (tot_fields) - { - uint k; - size= tot_fields*sizeof(char**); - if (!(char_ptrs= (uchar**)sql_calloc(size))) - goto error; - full_part_field_buffers= char_ptrs; - if (!(char_ptrs= (uchar**)sql_calloc(size))) - goto error; - restore_full_part_field_ptrs= char_ptrs; - size= (tot_fields + 1) * sizeof(char**); - if (!(char_ptrs= (uchar**)sql_calloc(size))) - goto error; - full_part_charset_field_array= (Field**)char_ptrs; - for (i= 0; i < tot_part_fields; i++) - { - full_part_charset_field_array[i]= part_charset_field_array[i]; - full_part_field_buffers[i]= part_field_buffers[i]; - } - k= tot_part_fields; - for (i= 0; i < tot_subpart_fields; i++) - { - uint j; - bool found= FALSE; - field= subpart_charset_field_array[i]; - - for (j= 0; j < tot_part_fields; j++) - { - if (field == part_charset_field_array[i]) - found= TRUE; - } - if (!found) - { - full_part_charset_field_array[k]= subpart_charset_field_array[i]; - full_part_field_buffers[k]= subpart_field_buffers[i]; - k++; - } - } - full_part_charset_field_array[k]= NULL; - } DBUG_RETURN(FALSE); error: mem_alloc_error(size); diff --git a/sql/partition_info.h b/sql/partition_info.h index 415f955d5d4..f232e761946 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -19,6 +19,8 @@ #include "partition_element.h" +#define MAX_STR_SIZE_PF 512 + class partition_info; /* Some function typedefs */ @@ -64,10 +66,9 @@ public: /* When we have various string fields we might need some preparation before and clean-up after calling the get_part_id_func's. We need - one such method for get_partition_id and one for - get_part_partition_id and one for get_subpartition_id. + one such method for get_part_partition_id and one for + get_subpartition_id. */ - get_part_id_func get_partition_id_charset; get_part_id_func get_part_partition_id_charset; get_subpart_id_func get_subpartition_id_charset; @@ -81,7 +82,6 @@ public: without duplicates, NULL-terminated. */ Field **full_part_field_array; - Field **full_part_charset_field_array; /* Set of all fields used in partition and subpartition expression. Required for testing of partition fields in write_set when @@ -97,10 +97,8 @@ public: */ uchar **part_field_buffers; uchar **subpart_field_buffers; - uchar **full_part_field_buffers; uchar **restore_part_field_ptrs; uchar **restore_subpart_field_ptrs; - uchar **restore_full_part_field_ptrs; Item *part_expr; Item *subpart_expr; @@ -124,6 +122,8 @@ public: union { longlong *range_int_array; LIST_PART_ENTRY *list_array; + part_column_list_val *range_col_array; + part_column_list_val *list_col_array; }; /******************************************** @@ -154,6 +154,10 @@ public: partition_element *curr_part_elem; partition_element *current_partition; + part_elem_value *curr_list_val; + uint curr_list_object; + uint num_columns; + /* These key_map's are used for Partitioning to enable quick decisions on whether we can derive more information about which partition to @@ -205,7 +209,7 @@ public: bool is_auto_partitioned; bool from_openfrm; bool has_null_value; - + bool column_list; partition_info() : get_partition_id(NULL), get_part_partition_id(NULL), @@ -214,11 +218,8 @@ public: part_charset_field_array(NULL), subpart_charset_field_array(NULL), full_part_field_array(NULL), - full_part_charset_field_array(NULL), part_field_buffers(NULL), subpart_field_buffers(NULL), - full_part_field_buffers(NULL), restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL), - restore_full_part_field_ptrs(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), list_array(NULL), err_value(0), @@ -226,6 +227,7 @@ public: part_func_string(NULL), subpart_func_string(NULL), part_state(NULL), curr_part_elem(NULL), current_partition(NULL), + curr_list_object(0), num_columns(0), default_engine_type(NULL), part_result_type(INT_RESULT), part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION), @@ -241,7 +243,7 @@ public: list_of_part_fields(FALSE), list_of_subpart_fields(FALSE), linear_hash_ind(FALSE), fixed(FALSE), is_auto_partitioned(FALSE), from_openfrm(FALSE), - has_null_value(FALSE) + has_null_value(FALSE), column_list(FALSE) { all_fields_in_PF.clear_all(); all_fields_in_PPF.clear_all(); @@ -271,16 +273,19 @@ public: uint start_no); char *has_unique_names(); bool check_engine_mix(handlerton *engine_type, bool default_engine); - bool check_range_constants(); - bool check_list_constants(); + bool check_range_constants(THD *thd); + bool check_list_constants(THD *thd); bool check_partition_info(THD *thd, handlerton **eng_type, handler *file, HA_CREATE_INFO *info, bool check_partition_function); void print_no_partition_found(TABLE *table); + part_column_list_val *add_column_value(); + bool set_part_expr(char *start_token, Item *item_ptr, + char *end_token, bool is_subpart); + static int compare_column_values(const void *a, const void *b); bool set_up_charset_field_preps(); private: static int list_part_cmp(const void* a, const void* b); - static int list_part_cmp_unsigned(const void* a, const void* b); bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info, uint start_no); bool set_up_default_subpartitions(handler *file, HA_CREATE_INFO *info); @@ -288,6 +293,9 @@ private: uint start_no); char *create_subpartition_name(uint subpart_no, const char *part_name); bool has_unique_name(partition_element *element); + bool fix_column_value_functions(THD *thd, + part_column_list_val *col_val, + uint part_id); }; uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5531ee71620..514dc06728d 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6180,6 +6180,16 @@ ER_TOO_LONG_FIELD_COMMENT ER_FUNC_INEXISTENT_NAME_COLLISION 42000 eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual" +ER_GLOBAL_PARTITION_INDEX_ERROR + eng "Partitioning of indexes only supported for global indexes" +ER_PARTITION_COLUMN_LIST_ERROR + eng "Inconsistency in usage of column lists for partitioning" +ER_WRONG_TYPE_COLUMN_VALUE_ERROR + eng "Partition column values of incorrect type" +ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR + eng "Too many fields in '%s'" +ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR + eng "Cannot use MAXVALUE as value in List partitioning" # When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in # mysql_priv.h with the new maximal additional length for explain_filename. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 2adbc44eb12..61f243ece1c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -323,6 +323,7 @@ void lex_start(THD *thd) lex->select_lex.select_number= 1; lex->length=0; lex->part_info= 0; + lex->global_flag= 0; lex->select_lex.in_sum_expr=0; lex->select_lex.ftfunc_list_alloc.empty(); lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 76fd5354c51..d714e3d0441 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1565,6 +1565,9 @@ typedef struct st_lex : public Query_tables_list /* Partition info structure filled in by PARTITION BY parse part */ partition_info *part_info; + /* Flag to index a global index created */ + bool global_flag; + /* The definer of the object being created (view, trigger, stored routine). I.e. the value of DEFINER clause. diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 61766e5c509..9684e842d40 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -18,16 +18,29 @@ to partitioning introduced in MySQL version 5.1. It contains functionality used by all handlers that support partitioning, such as the partitioning handler itself and the NDB handler. + (Much of the code in this file has been split into partition_info.cc and + the header files partition_info.h + partition_element.h + sql_partition.h) - The first version was written by Mikael Ronstrom. + The first version was written by Mikael Ronstrom 2004-2006. + Various parts of the optimizer code was written by Sergey Petrunia. + Code have been maintained by Mattias Jonsson. + The second version was written by Mikael Ronstrom 2006-2007 with some + final fixes for partition pruning in 2008-2009 with assistance from Sergey + Petrunia and Mattias Jonsson. - This version supports RANGE partitioning, LIST partitioning, HASH + The first version supports RANGE partitioning, LIST partitioning, HASH partitioning and composite partitioning (hereafter called subpartitioning) where each RANGE/LIST partitioning is HASH partitioned. The hash function can either be supplied by the user or by only a list of fields (also called KEY partitioning), where the MySQL server will use an internal hash function. There are quite a few defaults that can be used as well. + + The second version introduces a new variant of RANGE and LIST partitioning + which is often referred to as column lists in the code variables. This + enables a user to specify a set of columns and their concatenated value + as the partition value. By comparing the concatenation of these values + the proper partition can be choosen. */ /* Some general useful functions */ @@ -50,9 +63,11 @@ const LEX_STRING partition_keywords[]= { C_STRING_WITH_LEN("LIST") }, { C_STRING_WITH_LEN("KEY") }, { C_STRING_WITH_LEN("MAXVALUE") }, - { C_STRING_WITH_LEN("LINEAR ") } + { C_STRING_WITH_LEN("LINEAR ") }, + { C_STRING_WITH_LEN(" COLUMN_LIST") } }; static const char *part_str= "PARTITION"; +static const char *subpart_str= "SUBPARTITION"; static const char *sub_str= "SUB"; static const char *by_str= "BY"; static const char *space_str= " "; @@ -61,26 +76,23 @@ static const char *end_paren_str= ")"; static const char *begin_paren_str= "("; static const char *comma_str= ","; -static int get_part_id_charset_func_all(partition_info *part_info, - uint32 *part_id, - longlong *func_value); +int get_partition_id_list_col(partition_info *part_info, + uint32 *part_id, + longlong *func_value); +int get_partition_id_list(partition_info *part_info, + uint32 *part_id, + longlong *func_value); +int get_partition_id_range_col(partition_info *part_info, + uint32 *part_id, + longlong *func_value); +int get_partition_id_range(partition_info *part_info, + uint32 *part_id, + longlong *func_value); static int get_part_id_charset_func_part(partition_info *part_info, uint32 *part_id, longlong *func_value); static int get_part_id_charset_func_subpart(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -static int get_part_part_id_charset_func(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -static int get_subpart_id_charset_func(partition_info *part_info, - uint32 *part_id); -int get_partition_id_list(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_range(partition_info *part_info, - uint32 *part_id, - longlong *func_value); + uint32 *part_id); int get_partition_id_hash_nosub(partition_info *part_info, uint32 *part_id, longlong *func_value); @@ -93,30 +105,9 @@ int get_partition_id_linear_hash_nosub(partition_info *part_info, int get_partition_id_linear_key_nosub(partition_info *part_info, uint32 *part_id, longlong *func_value); -int get_partition_id_range_sub_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_range_sub_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_range_sub_linear_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_range_sub_linear_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_list_sub_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_list_sub_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_list_sub_linear_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_list_sub_linear_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value); +int get_partition_id_with_sub(partition_info *part_info, + uint32 *part_id, + longlong *func_value); int get_partition_id_hash_sub(partition_info *part_info, uint32 *part_id); int get_partition_id_key_sub(partition_info *part_info, @@ -134,14 +125,29 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter); uint32 get_next_partition_id_list(PARTITION_ITERATOR* part_iter); int get_part_iter_for_interval_via_mapping(partition_info *part_info, bool is_subpart, + uint32 *store_length_array, uchar *min_value, uchar *max_value, + uint min_len, uint max_len, uint flags, PARTITION_ITERATOR *part_iter); +int get_part_iter_for_interval_cols_via_map(partition_info *part_info, + bool is_subpart, + uint32 *store_length_array, + uchar *min_value, uchar *max_value, + uint min_len, uint max_len, + uint flags, + PARTITION_ITERATOR *part_iter); int get_part_iter_for_interval_via_walking(partition_info *part_info, bool is_subpart, + uint32 *store_length_array, uchar *min_value, uchar *max_value, + uint min_len, uint max_len, uint flags, PARTITION_ITERATOR *part_iter); +static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec); +static int cmp_rec_and_tuple_prune(part_column_list_val *val, + uint32 n_vals_in_rec, + bool tail_is_min); #ifdef WITH_PARTITION_STORAGE_ENGINE /* @@ -161,7 +167,7 @@ bool is_name_in_list(char *name, List list_names) { List_iterator names_it(list_names); - uint no_names= list_names.elements; + uint num_names= list_names.elements; uint i= 0; do @@ -169,7 +175,7 @@ bool is_name_in_list(char *name, char *list_name= names_it++; if (!(my_strcasecmp(system_charset_info, name, list_name))) return TRUE; - } while (++i < no_names); + } while (++i < num_names); return FALSE; } @@ -451,6 +457,7 @@ static bool set_up_field_array(TABLE *table, uint no_fields= 0; uint size_field_array; uint i= 0; + uint inx; partition_info *part_info= table->part_info; int result= FALSE; DBUG_ENTER("set_up_field_array"); @@ -461,6 +468,16 @@ static bool set_up_field_array(TABLE *table, if (field->flags & GET_FIXED_FIELDS_FLAG) no_fields++; } + if (no_fields > MAX_REF_PARTS) + { + char *ptr; + if (is_sub_part) + ptr= (char*)"subpartition function"; + else + ptr= (char*)"partition function"; + my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), ptr); + DBUG_RETURN(TRUE); + } if (no_fields == 0) { /* @@ -470,7 +487,7 @@ static bool set_up_field_array(TABLE *table, DBUG_RETURN(result); } size_field_array= (no_fields+1)*sizeof(Field*); - field_array= (Field**)sql_alloc(size_field_array); + field_array= (Field**)sql_calloc(size_field_array); if (unlikely(!field_array)) { mem_alloc_error(size_field_array); @@ -485,7 +502,30 @@ static bool set_up_field_array(TABLE *table, field->flags|= FIELD_IN_PART_FUNC_FLAG; if (likely(!result)) { - field_array[i++]= field; + if (!is_sub_part && part_info->column_list) + { + List_iterator it(part_info->part_field_list); + char *field_name; + + DBUG_ASSERT(no_fields == part_info->part_field_list.elements); + inx= 0; + do + { + field_name= it++; + if (!strcmp(field_name, field->field_name)) + break; + } while (++inx < no_fields); + if (inx == no_fields) + { + mem_alloc_error(1); + result= TRUE; + continue; + } + } + else + inx= i; + field_array[inx]= field; + i++; /* We check that the fields are proper. It is required for each @@ -564,7 +604,7 @@ static bool create_full_part_field_array(THD *thd, TABLE *table, no_part_fields++; } size_field_array= (no_part_fields+1)*sizeof(Field*); - field_array= (Field**)sql_alloc(size_field_array); + field_array= (Field**)sql_calloc(size_field_array); if (unlikely(!field_array)) { mem_alloc_error(size_field_array); @@ -776,7 +816,7 @@ static bool handle_list_of_fields(List_iterator it, goto end; } } - if (is_list_empty) + if (is_list_empty && part_info->part_type == HASH_PARTITION) { uint primary_key= table->s->primary_key; if (primary_key != MAX_KEY) @@ -868,7 +908,6 @@ int check_signed_flag(partition_info *part_info) table The table object part_info Reference to partitioning data structure is_sub_part Is the table subpartitioned as well - is_field_to_be_setup Flag if we are to set-up field arrays RETURN VALUE TRUE An error occurred, something was wrong with the @@ -891,8 +930,8 @@ int check_signed_flag(partition_info *part_info) on the field object. */ -bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, - bool is_sub_part, bool is_field_to_be_setup) +static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, + bool is_sub_part) { partition_info *part_info= table->part_info; uint dir_length, home_dir_length; @@ -985,8 +1024,7 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, if (unlikely(error)) { DBUG_PRINT("info", ("Field in partition function not part of table")); - if (is_field_to_be_setup) - clear_field_flag(table); + clear_field_flag(table); goto end; } thd->where= save_where; @@ -998,9 +1036,7 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, } if ((!is_sub_part) && (error= check_signed_flag(part_info))) goto end; - result= FALSE; - if (is_field_to_be_setup) - result= set_up_field_array(table, is_sub_part); + result= set_up_field_array(table, is_sub_part); if (!is_sub_part) part_info->fixed= TRUE; end: @@ -1283,64 +1319,47 @@ static void set_up_partition_func_pointers(partition_info *part_info) if (part_info->is_sub_partitioned()) { + part_info->get_partition_id= get_partition_id_with_sub; if (part_info->part_type == RANGE_PARTITION) { - part_info->get_part_partition_id= get_partition_id_range; + if (part_info->column_list) + part_info->get_part_partition_id= get_partition_id_range_col; + else + part_info->get_part_partition_id= get_partition_id_range; if (part_info->list_of_subpart_fields) { if (part_info->linear_hash_ind) - { - part_info->get_partition_id= get_partition_id_range_sub_linear_key; part_info->get_subpartition_id= get_partition_id_linear_key_sub; - } else - { - part_info->get_partition_id= get_partition_id_range_sub_key; part_info->get_subpartition_id= get_partition_id_key_sub; - } } else { if (part_info->linear_hash_ind) - { - part_info->get_partition_id= get_partition_id_range_sub_linear_hash; part_info->get_subpartition_id= get_partition_id_linear_hash_sub; - } else - { - part_info->get_partition_id= get_partition_id_range_sub_hash; part_info->get_subpartition_id= get_partition_id_hash_sub; - } } } else /* LIST Partitioning */ { - part_info->get_part_partition_id= get_partition_id_list; + if (part_info->column_list) + part_info->get_part_partition_id= get_partition_id_list_col; + else + part_info->get_part_partition_id= get_partition_id_list; if (part_info->list_of_subpart_fields) { if (part_info->linear_hash_ind) - { - part_info->get_partition_id= get_partition_id_list_sub_linear_key; part_info->get_subpartition_id= get_partition_id_linear_key_sub; - } else - { - part_info->get_partition_id= get_partition_id_list_sub_key; part_info->get_subpartition_id= get_partition_id_key_sub; - } } else { if (part_info->linear_hash_ind) - { - part_info->get_partition_id= get_partition_id_list_sub_linear_hash; part_info->get_subpartition_id= get_partition_id_linear_hash_sub; - } else - { - part_info->get_partition_id= get_partition_id_list_sub_hash; part_info->get_subpartition_id= get_partition_id_hash_sub; - } } } } @@ -1349,9 +1368,19 @@ static void set_up_partition_func_pointers(partition_info *part_info) part_info->get_part_partition_id= NULL; part_info->get_subpartition_id= NULL; if (part_info->part_type == RANGE_PARTITION) - part_info->get_partition_id= get_partition_id_range; + { + if (part_info->column_list) + part_info->get_partition_id= get_partition_id_range_col; + else + part_info->get_partition_id= get_partition_id_range; + } else if (part_info->part_type == LIST_PARTITION) - part_info->get_partition_id= get_partition_id_list; + { + if (part_info->column_list) + part_info->get_partition_id= get_partition_id_list_col; + else + part_info->get_partition_id= get_partition_id_list; + } else /* HASH partitioning */ { if (part_info->list_of_part_fields) @@ -1370,32 +1399,37 @@ static void set_up_partition_func_pointers(partition_info *part_info) } } } - if (part_info->full_part_charset_field_array) + /* + We need special functions to handle character sets since they require copy + of field pointers and restore afterwards. For subpartitioned tables we do + the copy and restore individually on the part and subpart parts. For non- + subpartitioned tables we use the same functions as used for the parts part + of subpartioning. + Thus for subpartitioned tables the get_partition_id is always + get_partition_id_with_sub, even when character sets exists. + */ + if (part_info->part_charset_field_array) { - DBUG_ASSERT(part_info->get_partition_id); - part_info->get_partition_id_charset= part_info->get_partition_id; - if (part_info->part_charset_field_array && - part_info->subpart_charset_field_array) - part_info->get_partition_id= get_part_id_charset_func_all; - else if (part_info->part_charset_field_array) - part_info->get_partition_id= get_part_id_charset_func_part; + if (part_info->is_sub_partitioned()) + { + DBUG_ASSERT(part_info->get_part_partition_id); + part_info->get_part_partition_id_charset= + part_info->get_part_partition_id; + part_info->get_part_partition_id= get_part_id_charset_func_part; + } else - part_info->get_partition_id= get_part_id_charset_func_subpart; - } - if (part_info->part_charset_field_array && - part_info->is_sub_partitioned()) - { - DBUG_ASSERT(part_info->get_part_partition_id); - part_info->get_part_partition_id_charset= - part_info->get_part_partition_id; - part_info->get_part_partition_id= get_part_part_id_charset_func; + { + DBUG_ASSERT(part_info->get_partition_id); + part_info->get_part_partition_id_charset= part_info->get_partition_id; + part_info->get_partition_id= get_part_id_charset_func_part; + } } if (part_info->subpart_charset_field_array) { DBUG_ASSERT(part_info->get_subpartition_id); part_info->get_subpartition_id_charset= part_info->get_subpartition_id; - part_info->get_subpartition_id= get_subpart_id_charset_func; + part_info->get_subpartition_id= get_part_id_charset_func_subpart; } DBUG_VOID_RETURN; } @@ -1603,12 +1637,12 @@ bool fix_partition_func(THD *thd, TABLE *table, else { if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr, - table, TRUE, TRUE))) + table, TRUE))) goto end; if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT)) { my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), - "SUBPARTITION"); + subpart_str); goto end; } } @@ -1631,7 +1665,7 @@ bool fix_partition_func(THD *thd, TABLE *table, else { if (unlikely(fix_fields_part_func(thd, part_info->part_expr, - table, FALSE, TRUE))) + table, FALSE))) goto end; if (unlikely(part_info->part_expr->result_type() != INT_RESULT)) { @@ -1644,19 +1678,28 @@ bool fix_partition_func(THD *thd, TABLE *table, else { const char *error_str; - if (unlikely(fix_fields_part_func(thd, part_info->part_expr, - table, FALSE, TRUE))) - goto end; + if (part_info->column_list) + { + List_iterator it(part_info->part_field_list); + if (unlikely(handle_list_of_fields(it, table, part_info, FALSE))) + goto end; + } + else + { + if (unlikely(fix_fields_part_func(thd, part_info->part_expr, + table, FALSE))) + goto end; + } if (part_info->part_type == RANGE_PARTITION) { error_str= partition_keywords[PKW_RANGE].str; - if (unlikely(part_info->check_range_constants())) + if (unlikely(part_info->check_range_constants(thd))) goto end; } else if (part_info->part_type == LIST_PARTITION) { error_str= partition_keywords[PKW_LIST].str; - if (unlikely(part_info->check_list_constants())) + if (unlikely(part_info->check_list_constants(thd))) goto end; } else @@ -1670,7 +1713,8 @@ bool fix_partition_func(THD *thd, TABLE *table, my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str); goto end; } - if (unlikely(part_info->part_expr->result_type() != INT_RESULT)) + if (unlikely(!part_info->column_list && + part_info->part_expr->result_type() != INT_RESULT)) { my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str); goto end; @@ -1723,9 +1767,9 @@ end: static int add_write(File fptr, const char *buf, uint len) { - uint len_written= my_write(fptr, (const uchar*)buf, len, MYF(0)); + uint ret_code= my_write(fptr, (const uchar*)buf, len, MYF(MY_FNABP)); - if (likely(len == len_written)) + if (likely(ret_code == 0)) return 0; else return 1; @@ -1774,14 +1818,8 @@ static int add_begin_parenthesis(File fptr) static int add_part_key_word(File fptr, const char *key_string) { int err= add_string(fptr, key_string); - err+= add_space(fptr); - return err + add_begin_parenthesis(fptr); -} - -static int add_hash(File fptr) -{ - return add_part_key_word(fptr, partition_keywords[PKW_HASH].str); + return err; } static int add_partition(File fptr) @@ -1812,15 +1850,15 @@ static int add_subpartition_by(File fptr) return err + add_partition_by(fptr); } -static int add_key_partition(File fptr, List field_list) +static int add_part_field_list(File fptr, List field_list) { uint i, no_fields; - int err; + int err= 0; List_iterator part_it(field_list); - err= add_part_key_word(fptr, partition_keywords[PKW_KEY].str); no_fields= field_list.elements; i= 0; + err+= add_begin_parenthesis(fptr); while (i < no_fields) { const char *field_str= part_it++; @@ -1836,6 +1874,7 @@ static int add_key_partition(File fptr, List field_list) err+= add_comma(fptr); i++; } + err+= add_end_parenthesis(fptr); return err; } @@ -1945,24 +1984,88 @@ static int add_partition_options(File fptr, partition_element *p_elem) return err + add_engine(fptr,p_elem->engine_type); } -static int add_partition_values(File fptr, partition_info *part_info, partition_element *p_elem) +static int add_column_list_values(File fptr, partition_info *part_info, + part_elem_value *list_value) +{ + int err= 0; + uint i; + uint no_elements= part_info->part_field_list.elements; + err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); + err+= add_begin_parenthesis(fptr); + for (i= 0; i < no_elements; i++) + { + part_column_list_val *col_val= &list_value->col_val_array[i]; + if (col_val->max_value) + err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str); + else if (col_val->null_value) + err+= add_string(fptr, "NULL"); + else + { + char buffer[MAX_STR_SIZE_PF]; + String str(buffer, sizeof(buffer), &my_charset_bin); + Item *item_expr= col_val->item_expression; + if (!col_val->fixed && + (item_expr->fix_fields(current_thd, (Item**)0) || + (!item_expr->const_item()))) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + return 1; + } + col_val->fixed= 1; + if (item_expr->null_value) + err+= add_string(fptr, "NULL"); + else + { + String *res= item_expr->val_str(&str); + if (!res) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + return 1; + } + if (item_expr->result_type() == STRING_RESULT) + err+= add_string(fptr,"'"); + err+= add_string_object(fptr, res); + if (item_expr->result_type() == STRING_RESULT) + err+= add_string(fptr,"'"); + } + } + if (i != (no_elements - 1)) + err+= add_string(fptr, comma_str); + } + err+= add_end_parenthesis(fptr); + return err; +} + +static int add_partition_values(File fptr, partition_info *part_info, + partition_element *p_elem) { int err= 0; if (part_info->part_type == RANGE_PARTITION) { err+= add_string(fptr, " VALUES LESS THAN "); - if (!p_elem->max_value) + if (part_info->column_list) { + List_iterator list_val_it(p_elem->list_val_list); + part_elem_value *list_value= list_val_it++; err+= add_begin_parenthesis(fptr); - if (p_elem->signed_flag) - err+= add_int(fptr, p_elem->range_value); - else - err+= add_uint(fptr, p_elem->range_value); + err+= add_column_list_values(fptr, part_info, list_value); err+= add_end_parenthesis(fptr); } else - err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str); + { + if (!p_elem->max_value) + { + err+= add_begin_parenthesis(fptr); + if (p_elem->signed_flag) + err+= add_int(fptr, p_elem->range_value); + else + err+= add_uint(fptr, p_elem->range_value); + err+= add_end_parenthesis(fptr); + } + else + err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str); + } } else if (part_info->part_type == LIST_PARTITION) { @@ -1987,10 +2090,15 @@ static int add_partition_values(File fptr, partition_info *part_info, partition_ { part_elem_value *list_value= list_val_it++; - if (!list_value->unsigned_flag) - err+= add_int(fptr, list_value->value); + if (part_info->column_list) + err+= add_column_list_values(fptr, part_info, list_value); else - err+= add_uint(fptr, list_value->value); + { + if (!list_value->unsigned_flag) + err+= add_int(fptr, list_value->value); + else + err+= add_uint(fptr, list_value->value); + } if (i != (no_items-1)) err+= add_comma(fptr); } while (++i < no_items); @@ -2073,9 +2181,12 @@ char *generate_partition_syntax(partition_info *part_info, if (part_info->linear_hash_ind) err+= add_string(fptr, partition_keywords[PKW_LINEAR].str); if (part_info->list_of_part_fields) - err+= add_key_partition(fptr, part_info->part_field_list); + { + err+= add_part_key_word(fptr, partition_keywords[PKW_KEY].str); + err+= add_part_field_list(fptr, part_info->part_field_list); + } else - err+= add_hash(fptr); + err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str); break; default: DBUG_ASSERT(0); @@ -2085,9 +2196,17 @@ char *generate_partition_syntax(partition_info *part_info, DBUG_RETURN(NULL); } if (part_info->part_expr) + { + err+= add_begin_parenthesis(fptr); err+= add_string_len(fptr, part_info->part_func_string, part_info->part_func_len); - err+= add_end_parenthesis(fptr); + err+= add_end_parenthesis(fptr); + } + else if (part_info->column_list) + { + err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); + err+= add_part_field_list(fptr, part_info->part_field_list); + } if ((!part_info->use_default_no_partitions) && part_info->use_default_partitions) { @@ -2103,13 +2222,19 @@ char *generate_partition_syntax(partition_info *part_info, if (part_info->linear_hash_ind) err+= add_string(fptr, partition_keywords[PKW_LINEAR].str); if (part_info->list_of_subpart_fields) - err+= add_key_partition(fptr, part_info->subpart_field_list); + { + add_part_key_word(fptr, partition_keywords[PKW_KEY].str); + add_part_field_list(fptr, part_info->subpart_field_list); + } else - err+= add_hash(fptr); + err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str); if (part_info->subpart_expr) + { + err+= add_begin_parenthesis(fptr); err+= add_string_len(fptr, part_info->subpart_func_string, part_info->subpart_func_len); - err+= add_end_parenthesis(fptr); + err+= add_end_parenthesis(fptr); + } if ((!part_info->use_default_no_subpartitions) && part_info->use_default_subpartitions) { @@ -2446,7 +2571,7 @@ static uint32 get_part_id_linear_key(partition_info *part_info, uint no_parts, longlong *func_value) { - DBUG_ENTER("get_partition_id_linear_key"); + DBUG_ENTER("get_part_id_linear_key"); *func_value= calculate_key_value(field_array); DBUG_RETURN(get_part_id_from_linear_hash(*func_value, @@ -2537,6 +2662,44 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr) return; } +/* + This function is used to calculate the partition id where all partition + fields have been prepared to point to a record where the partition field + values are bound. + + SYNOPSIS + get_partition_id() + part_info A reference to the partition_info struct where all the + desired information is given + out:part_id The partition id is returned through this pointer + out: func_value Value of partition function (longlong) + + RETURN VALUE + part_id Partition id of partition that would contain + row with given values of PF-fields + HA_ERR_NO_PARTITION_FOUND The fields of the partition function didn't + fit into any partition and thus the values of + the PF-fields are not allowed. + + DESCRIPTION + A routine used from write_row, update_row and delete_row from any + handler supporting partitioning. It is also a support routine for + get_partition_set used to find the set of partitions needed to scan + for a certain index scan or full table scan. + + It is actually 9 different variants of this function which are called + through a function pointer. + + get_partition_id_list + get_partition_id_list_col + get_partition_id_range + get_partition_id_range_col + get_partition_id_hash_nosub + get_partition_id_key_nosub + get_partition_id_linear_hash_nosub + get_partition_id_linear_key_nosub + get_partition_id_with_sub +*/ /* This function is used to calculate the main partition to use in the case of @@ -2558,67 +2721,26 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr) DESCRIPTION - It is actually 6 different variants of this function which are called + It is actually 8 different variants of this function which are called through a function pointer. get_partition_id_list + get_partition_id_list_col get_partition_id_range + get_partition_id_range_col get_partition_id_hash_nosub get_partition_id_key_nosub - get_partition_id_linear_hash_nosub + get_partition_id_linhash_nosub get_partition_id_linear_key_nosub */ -static int get_part_id_charset_func_subpart(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - int res; - copy_to_part_field_buffers(part_info->subpart_charset_field_array, - part_info->subpart_field_buffers, - part_info->restore_subpart_field_ptrs); - res= part_info->get_partition_id_charset(part_info, part_id, func_value); - restore_part_field_pointers(part_info->subpart_charset_field_array, - part_info->restore_subpart_field_ptrs); - return res; -} - - static int get_part_id_charset_func_part(partition_info *part_info, uint32 *part_id, longlong *func_value) { int res; - copy_to_part_field_buffers(part_info->part_charset_field_array, - part_info->part_field_buffers, - part_info->restore_part_field_ptrs); - res= part_info->get_partition_id_charset(part_info, part_id, func_value); - restore_part_field_pointers(part_info->part_charset_field_array, - part_info->restore_part_field_ptrs); - return res; -} + DBUG_ENTER("get_part_id_charset_func_part"); - -static int get_part_id_charset_func_all(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - int res; - copy_to_part_field_buffers(part_info->full_part_field_array, - part_info->full_part_field_buffers, - part_info->restore_full_part_field_ptrs); - res= part_info->get_partition_id_charset(part_info, part_id, func_value); - restore_part_field_pointers(part_info->full_part_field_array, - part_info->restore_full_part_field_ptrs); - return res; -} - - -static int get_part_part_id_charset_func(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - int res; copy_to_part_field_buffers(part_info->part_charset_field_array, part_info->part_field_buffers, part_info->restore_part_field_ptrs); @@ -2626,21 +2748,58 @@ static int get_part_part_id_charset_func(partition_info *part_info, part_id, func_value); restore_part_field_pointers(part_info->part_charset_field_array, part_info->restore_part_field_ptrs); - return res; + DBUG_RETURN(res); } -static int get_subpart_id_charset_func(partition_info *part_info, - uint32 *part_id) +static int get_part_id_charset_func_subpart(partition_info *part_info, + uint32 *part_id) { int res; + DBUG_ENTER("get_part_id_charset_func_subpart"); + copy_to_part_field_buffers(part_info->subpart_charset_field_array, part_info->subpart_field_buffers, part_info->restore_subpart_field_ptrs); res= part_info->get_subpartition_id_charset(part_info, part_id); restore_part_field_pointers(part_info->subpart_charset_field_array, part_info->restore_subpart_field_ptrs); - return res; + DBUG_RETURN(res); +} + +int get_partition_id_list_col(partition_info *part_info, + uint32 *part_id, + longlong *func_value) +{ + part_column_list_val *list_col_array= part_info->list_col_array; + uint no_columns= part_info->part_field_list.elements; + int list_index, cmp; + int min_list_index= 0; + int max_list_index= part_info->no_list_values - 1; + DBUG_ENTER("get_partition_id_list_col"); + + while (max_list_index >= min_list_index) + { + list_index= (max_list_index + min_list_index) >> 1; + cmp= cmp_rec_and_tuple(list_col_array + list_index*no_columns, + no_columns); + if (cmp > 0) + min_list_index= list_index + 1; + else if (cmp < 0) + { + if (!list_index) + goto notfound; + max_list_index= list_index - 1; + } + else + { + *part_id= (uint32)list_col_array[list_index].partition_id; + DBUG_RETURN(0); + } + } +notfound: + *part_id= 0; + DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND); } @@ -2735,6 +2894,44 @@ notfound: The edge of corresponding sub-array of part_info->list_array */ +uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info, + bool left_endpoint, + bool include_endpoint, + uint32 nparts) +{ + part_column_list_val *list_col_array= part_info->list_col_array; + uint no_columns= part_info->part_field_list.elements; + int list_index, cmp; + uint min_list_index= 0; + uint max_list_index= part_info->no_list_values - 1; + bool tailf= !(left_endpoint ^ include_endpoint); + DBUG_ENTER("get_partition_id_cols_list_for_endpoint"); + + do + { + list_index= (max_list_index + min_list_index) >> 1; + cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*no_columns, + nparts, tailf); + if (cmp > 0) + min_list_index= list_index + 1; + else if (cmp < 0) + { + if (!list_index) + goto notfound; + max_list_index= list_index - 1; + } + else + { + DBUG_RETURN(list_index + test(left_endpoint ^ include_endpoint)); + } + } while (max_list_index >= min_list_index); +notfound: + if (cmp > 0) + list_index++; + DBUG_RETURN(list_index); +} + + uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info, bool left_endpoint, bool include_endpoint) @@ -2795,6 +2992,44 @@ notfound: } +int get_partition_id_range_col(partition_info *part_info, + uint32 *part_id, + longlong *func_value) +{ + part_column_list_val *range_col_array= part_info->range_col_array; + uint no_columns= part_info->part_field_list.elements; + uint max_partition= part_info->no_parts - 1; + uint min_part_id= 0; + uint max_part_id= max_partition; + uint loc_part_id; + DBUG_ENTER("get_partition_id_range_col"); + + while (max_part_id > min_part_id) + { + loc_part_id= (max_part_id + min_part_id + 1) >> 1; + if (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, + no_columns) >= 0) + min_part_id= loc_part_id + 1; + else + max_part_id= loc_part_id - 1; + } + loc_part_id= max_part_id; + if (loc_part_id != max_partition) + if (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, + no_columns) >= 0) + loc_part_id++; + *part_id= (uint32)loc_part_id; + if (loc_part_id == max_partition && + (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, + no_columns) >= 0)) + DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND); + + DBUG_PRINT("exit",("partition: %d", *part_id)); + DBUG_RETURN(0); + return 0; +} + + int get_partition_id_range(partition_info *part_info, uint32 *part_id, longlong *func_value) @@ -2995,8 +3230,8 @@ int get_partition_id_key_nosub(partition_info *part_info, int get_partition_id_linear_key_nosub(partition_info *part_info, - uint32 *part_id, - longlong *func_value) + uint32 *part_id, + longlong *func_value) { *part_id= get_part_id_linear_key(part_info, part_info->part_field_array, @@ -3005,215 +3240,27 @@ int get_partition_id_linear_key_nosub(partition_info *part_info, } -int get_partition_id_range_sub_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value) +int get_partition_id_with_sub(partition_info *part_info, + uint32 *part_id, + longlong *func_value) { uint32 loc_part_id, sub_part_id; uint no_subparts; - longlong local_func_value; int error; - DBUG_ENTER("get_partition_id_range_sub_hash"); - LINT_INIT(loc_part_id); - LINT_INIT(sub_part_id); + DBUG_ENTER("get_partition_id_with_sub"); - if (unlikely((error= get_partition_id_range(part_info, &loc_part_id, - func_value)))) + if (unlikely((error= part_info->get_part_partition_id(part_info, + &loc_part_id, + func_value)))) { DBUG_RETURN(error); } no_subparts= part_info->no_subparts; - if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr, - &sub_part_id, &local_func_value)))) + if (unlikely((error= part_info->get_subpartition_id(part_info, + &sub_part_id)))) { DBUG_RETURN(error); - } - - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_range_sub_linear_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_range_sub_linear_hash"); - LINT_INIT(loc_part_id); - LINT_INIT(sub_part_id); - - if (unlikely((error= get_partition_id_range(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts, - part_info->subpart_expr, - &sub_part_id, - &local_func_value)))) - { - DBUG_RETURN(error); - } - - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_range_sub_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_range_sub_key"); - LINT_INIT(loc_part_id); - - if (unlikely((error= get_partition_id_range(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - sub_part_id= get_part_id_key(part_info->subpart_field_array, - no_subparts, &local_func_value); - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_range_sub_linear_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_range_sub_linear_key"); - LINT_INIT(loc_part_id); - - if (unlikely((error= get_partition_id_range(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - sub_part_id= get_part_id_linear_key(part_info, - part_info->subpart_field_array, - no_subparts, &local_func_value); - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_list_sub_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_list_sub_hash"); - LINT_INIT(sub_part_id); - - if (unlikely((error= get_partition_id_list(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr, - &sub_part_id, &local_func_value)))) - { - DBUG_RETURN(error); - } - - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_list_sub_linear_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_list_sub_linear_hash"); - LINT_INIT(sub_part_id); - - if (unlikely((error= get_partition_id_list(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts, - part_info->subpart_expr, - &sub_part_id, - &local_func_value)))) - { - DBUG_RETURN(error); - } - - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_list_sub_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_range_sub_key"); - - if (unlikely((error= get_partition_id_list(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - sub_part_id= get_part_id_key(part_info->subpart_field_array, - no_subparts, &local_func_value); - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_list_sub_linear_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_list_sub_linear_key"); - - if (unlikely((error= get_partition_id_list(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - sub_part_id= get_part_id_linear_key(part_info, - part_info->subpart_field_array, - no_subparts, &local_func_value); + } *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); DBUG_RETURN(0); } @@ -4226,6 +4273,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, partition_info *tab_part_info= table->part_info; partition_info *alt_part_info= thd->work_part_info; uint flags= 0; + bool is_last_partition_reorged; + part_elem_value *tab_max_elem_val= NULL; + part_elem_value *alt_max_elem_val= NULL; + longlong tab_max_range= 0, alt_max_range= 0; + if (!tab_part_info) { my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); @@ -4280,34 +4332,43 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, ((flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE)) != 0); DBUG_PRINT("info", ("*fast_alter_partition: %d flags: 0x%x", *fast_alter_partition, flags)); - if (((alter_info->flags & ALTER_ADD_PARTITION) || - (alter_info->flags & ALTER_REORGANIZE_PARTITION)) && - (thd->work_part_info->part_type != tab_part_info->part_type) && - (thd->work_part_info->part_type != NOT_A_PARTITION)) + if ((alter_info->flags & ALTER_ADD_PARTITION) || + (alter_info->flags & ALTER_REORGANIZE_PARTITION)) { - if (thd->work_part_info->part_type == RANGE_PARTITION) + if ((tab_part_info->column_list && + alt_part_info->num_columns != tab_part_info->num_columns) || + (!tab_part_info->column_list && alt_part_info->num_columns)) { - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); } - else if (thd->work_part_info->part_type == LIST_PARTITION) + if ((thd->work_part_info->part_type != tab_part_info->part_type) && + (thd->work_part_info->part_type != NOT_A_PARTITION)) { - DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION); - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "LIST", "IN"); + if (thd->work_part_info->part_type == RANGE_PARTITION) + { + my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN"); + } + else if (thd->work_part_info->part_type == LIST_PARTITION) + { + DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION); + my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "LIST", "IN"); + } + else if (tab_part_info->part_type == RANGE_PARTITION) + { + my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN"); + } + else + { + DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION); + my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), + "LIST", "IN"); + } + DBUG_RETURN(TRUE); } - else if (tab_part_info->part_type == RANGE_PARTITION) - { - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); - } - else - { - DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION); - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "LIST", "IN"); - } - DBUG_RETURN(TRUE); } if (alter_info->flags & ALTER_ADD_PARTITION) { @@ -4747,7 +4808,6 @@ state of p1. */ uint no_parts_reorged= alter_info->partition_names.elements; uint no_parts_new= thd->work_part_info->partitions.elements; - partition_info *alt_part_info= thd->work_part_info; uint check_total_partitions; tab_part_info->is_auto_partitioned= FALSE; @@ -4827,9 +4887,7 @@ the generated partition syntax in a correct manner. uint part_count= 0; bool found_first= FALSE; bool found_last= FALSE; - bool is_last_partition_reorged; uint drop_count= 0; - longlong tab_max_range= 0, alt_max_range= 0; do { partition_element *part_elem= tab_it++; @@ -4839,7 +4897,13 @@ the generated partition syntax in a correct manner. { is_last_partition_reorged= TRUE; drop_count++; - tab_max_range= part_elem->range_value; + if (tab_part_info->column_list) + { + List_iterator p(part_elem->list_val_list); + tab_max_elem_val= p++; + } + else + tab_max_range= part_elem->range_value; if (*fast_alter_partition && tab_part_info->temp_partitions.push_back(part_elem)) { @@ -4851,13 +4915,21 @@ the generated partition syntax in a correct manner. if (!found_first) { uint alt_part_count= 0; - found_first= TRUE; + partition_element *alt_part_elem; List_iterator alt_it(alt_part_info->partitions); + found_first= TRUE; do { - partition_element *alt_part_elem= alt_it++; - alt_max_range= alt_part_elem->range_value; + alt_part_elem= alt_it++; + if (tab_part_info->column_list) + { + List_iterator p(alt_part_elem->list_val_list); + alt_max_elem_val= p++; + } + else + alt_max_range= alt_part_elem->range_value; + if (*fast_alter_partition) alt_part_elem->part_state= PART_TO_BE_ADDED; if (alt_part_count == 0) @@ -4885,25 +4957,6 @@ the generated partition syntax in a correct manner. my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE"); DBUG_RETURN(TRUE); } - if (tab_part_info->part_type == RANGE_PARTITION && - ((is_last_partition_reorged && - alt_max_range < tab_max_range) || - (!is_last_partition_reorged && - alt_max_range != tab_max_range))) - { - /* - For range partitioning the total resulting range before and - after the change must be the same except in one case. This is - when the last partition is reorganised, in this case it is - acceptable to increase the total range. - The reason is that it is not allowed to have "holes" in the - middle of the ranges and thus we should not allow to reorganise - to create "holes". Also we should not allow using REORGANIZE - to drop data. - */ - my_error(ER_REORG_OUTSIDE_RANGE, MYF(0)); - DBUG_RETURN(TRUE); - } tab_part_info->no_parts= check_total_partitions; } } @@ -4923,10 +4976,42 @@ the generated partition syntax in a correct manner. tab_part_info->use_default_no_subpartitions= FALSE; } if (tab_part_info->check_partition_info(thd, (handlerton**)NULL, - table->file, ULL(0), FALSE)) + table->file, ULL(0), TRUE)) { DBUG_RETURN(TRUE); } + /* + The check below needs to be performed after check_partition_info + since this function "fixes" the item trees of the new partitions + to reorganize into + */ + if (alter_info->flags == ALTER_REORGANIZE_PARTITION && + tab_part_info->part_type == RANGE_PARTITION && + ((is_last_partition_reorged && + (tab_part_info->column_list ? + (tab_part_info->compare_column_values( + alt_max_elem_val->col_val_array, + tab_max_elem_val->col_val_array) < 0) : + alt_max_range < tab_max_range)) || + (!is_last_partition_reorged && + (tab_part_info->column_list ? + (tab_part_info->compare_column_values( + alt_max_elem_val->col_val_array, + tab_max_elem_val->col_val_array) != 0) : + alt_max_range != tab_max_range)))) + { + /* + For range partitioning the total resulting range before and + after the change must be the same except in one case. This is + when the last partition is reorganised, in this case it is + acceptable to increase the total range. + The reason is that it is not allowed to have "holes" in the + middle of the ranges and thus we should not allow to reorganise + to create "holes". + */ + my_error(ER_REORG_OUTSIDE_RANGE, MYF(0)); + DBUG_RETURN(TRUE); + } } } else @@ -6565,16 +6650,19 @@ void make_used_partitions_str(partition_info *part_info, String *parts_str) IMPLEMENTATION There are two available interval analyzer functions: (1) get_part_iter_for_interval_via_mapping - (2) get_part_iter_for_interval_via_walking + (2) get_part_iter_for_interval_cols_via_map + (3) get_part_iter_for_interval_via_walking They both have limited applicability: (1) is applicable for "PARTITION BY (func(t.field))", where func is a monotonic function. - - (2) is applicable for + + (2) is applicable for "PARTITION BY COLUMN_LIST (field_list) + + (3) is applicable for "[SUB]PARTITION BY (any_func(t.integer_field))" - If both are applicable, (1) is preferred over (2). + If both (1) and (3) are applicable, (1) is preferred over (3). This function sets part_info::get_part_iter_for_interval according to this criteria, and also sets some auxilary fields that the function @@ -6594,10 +6682,19 @@ static void set_up_range_analysis_info(partition_info *part_info) switch (part_info->part_type) { case RANGE_PARTITION: case LIST_PARTITION: - if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC) + if (!part_info->column_list) + { + if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC) + { + part_info->get_part_iter_for_interval= + get_part_iter_for_interval_via_mapping; + goto setup_subparts; + } + } + else { part_info->get_part_iter_for_interval= - get_part_iter_for_interval_via_mapping; + get_part_iter_for_interval_cols_via_map; goto setup_subparts; } default: @@ -6648,9 +6745,104 @@ setup_subparts: } +/* TODO Commenting those functions */ +uint32 store_tuple_to_record(Field **pfield, + uint32 *store_length_array, + uchar *value, + uchar *value_end) +{ + // see store_key_image_to_rec + uint32 nparts= 0; + uchar *loc_value; + while (value < value_end) + { + loc_value= value; + if ((*pfield)->real_maybe_null()) + { + if (*loc_value) + { + (*pfield)->set_null(); + } + (*pfield)->set_notnull(); + loc_value++; + } + uint len= (*pfield)->pack_length(); + (*pfield)->set_key_image(loc_value, len); + value+= *store_length_array; + store_length_array++; + nparts++; + pfield++; + } + return nparts; +} + +/* + RANGE(columns) partitioning: compare value bound and probe tuple. + + The value bound always is a full tuple (but may include MIN_VALUE and + MAX_VALUE special values). + + The probe tuple may be a prefix of partitioning tuple. The tail_is_min + parameter specifies whether the suffix components should be assumed to + hold MIN_VALUE or MAX_VALUE +*/ + +static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec) +{ + partition_info *part_info= val->part_info; + Field **field= part_info->part_field_array; + Field **fields_end= field + nvals_in_rec; + int res; + + for (; field != fields_end; field++, val++) + { + if (val->max_value) + return -1; + if ((*field)->is_null()) + { + if (val->null_value) + continue; + return -1; + } + if (val->null_value) + return +1; + res= (*field)->cmp((const uchar*)val->column_value); + if (res) + return res; + } + return 0; +} + + +static int cmp_rec_and_tuple_prune(part_column_list_val *val, + uint32 n_vals_in_rec, + bool tail_is_min) +{ + int cmp; + Field **field; + partition_info *part_info; + if ((cmp= cmp_rec_and_tuple(val, n_vals_in_rec))) + return cmp; + part_info= val->part_info; + field= part_info->part_field_array + n_vals_in_rec; + for (; *field; field++, val++) + { + if (tail_is_min) + return -1; + if (!tail_is_min && !val->max_value) + return +1; + } + return 0; +} + + typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint, bool include_endpoint); +typedef uint32 (*get_col_endpoint_func)(partition_info*, bool left_endpoint, + bool include_endpoint, + uint32 no_parts); + /* Partitioning Interval Analysis: Initialize the iterator for "mapping" case @@ -6686,17 +6878,132 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint, -1 - All partitions would match (iterator not initialized) */ +uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, + bool left_endpoint, + bool include_endpoint, + uint32 nparts) +{ + uint max_partition= part_info->no_parts - 1; + uint min_part_id= 0, max_part_id= max_partition, loc_part_id; + part_column_list_val *range_col_array= part_info->range_col_array; + uint no_columns= part_info->part_field_list.elements; + bool tailf= !(left_endpoint ^ include_endpoint); + DBUG_ENTER("get_partition_id_cols_range_for_endpoint"); + + /* Get the partitioning function value for the endpoint */ + while (max_part_id > min_part_id) + { + loc_part_id= (max_part_id + min_part_id + 1) >> 1; + if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*no_columns, + nparts, tailf) >= 0) + min_part_id= loc_part_id + 1; + else + max_part_id= loc_part_id - 1; + } + loc_part_id= max_part_id; + if (loc_part_id < max_partition && + cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*no_columns, + nparts, tailf) >= 0 + ) + { + loc_part_id++; + } + if (left_endpoint) + { + if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*no_columns, + nparts, tailf) >= 0) + loc_part_id++; + } + else + { + if (loc_part_id < max_partition) + { + int res= cmp_rec_and_tuple_prune(range_col_array + + loc_part_id * no_columns, + nparts, tailf); + if (!res) + loc_part_id += test(include_endpoint); + else if (res > 0) + loc_part_id++; + } + loc_part_id++; + } + DBUG_RETURN(loc_part_id); +} + + +int get_part_iter_for_interval_cols_via_map(partition_info *part_info, + bool is_subpart, + uint32 *store_length_array, + uchar *min_value, uchar *max_value, + uint min_len, uint max_len, + uint flags, + PARTITION_ITERATOR *part_iter) +{ + uint32 nparts; + get_col_endpoint_func get_col_endpoint; + DBUG_ENTER("get_part_iter_for_interval_cols_via_map"); + + if (part_info->part_type == RANGE_PARTITION) + { + get_col_endpoint= get_partition_id_cols_range_for_endpoint; + part_iter->get_next= get_next_partition_id_range; + } + else + { + get_col_endpoint= get_partition_id_cols_list_for_endpoint; + part_iter->get_next= get_next_partition_id_list; + part_iter->part_info= part_info; + } + if (flags & NO_MIN_RANGE) + part_iter->part_nums.start= part_iter->part_nums.cur= 0; + else + { + // Copy from min_value to record + nparts= store_tuple_to_record(part_info->part_field_array, + store_length_array, + min_value, + min_value + min_len); + part_iter->part_nums.start= part_iter->part_nums.cur= + get_col_endpoint(part_info, TRUE, !(flags & NEAR_MIN), + nparts); + } + if (flags & NO_MAX_RANGE) + part_iter->part_nums.end= part_info->no_parts; + else + { + // Copy from max_value to record + nparts= store_tuple_to_record(part_info->part_field_array, + store_length_array, + max_value, + max_value + max_len); + part_iter->part_nums.end= get_col_endpoint(part_info, FALSE, + !(flags & NEAR_MAX), + nparts); + } + if (part_iter->part_nums.start == part_iter->part_nums.end) + DBUG_RETURN(0); + DBUG_RETURN(1); +} + + int get_part_iter_for_interval_via_mapping(partition_info *part_info, bool is_subpart, + uint32 *store_length_array, /* ignored */ uchar *min_value, uchar *max_value, + uint min_len, uint max_len, /* ignored */ uint flags, PARTITION_ITERATOR *part_iter) { - DBUG_ASSERT(!is_subpart); Field *field= part_info->part_field_array[0]; uint32 max_endpoint_val; get_endpoint_func get_endpoint; uint field_len= field->pack_length_in_rec(); + DBUG_ENTER("get_part_iter_for_interval_via_mapping"); + DBUG_ASSERT(!is_subpart); + (void) store_length_array; + (void)min_len; + (void)max_len; part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; if (part_info->part_type == RANGE_PARTITION) @@ -6728,7 +7035,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, part_iter->part_nums.start= part_iter->part_nums.end= 0; part_iter->part_nums.cur= 0; part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE; - return -1; + DBUG_RETURN(-1); } } else @@ -6747,7 +7054,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, { /* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */ part_iter->part_nums.end= 0; - return 1; + DBUG_RETURN(1); } } else @@ -6767,7 +7074,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp); part_iter->part_nums.cur= part_iter->part_nums.start; if (part_iter->part_nums.start == max_endpoint_val) - return 0; /* No partitions */ + DBUG_RETURN(0); /* No partitions */ } } @@ -6781,9 +7088,9 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp); if (part_iter->part_nums.start >= part_iter->part_nums.end && !part_iter->ret_null_part) - return 0; /* No partitions */ + DBUG_RETURN(0); /* No partitions */ } - return 1; /* Ok, iterator initialized */ + DBUG_RETURN(1); /* Ok, iterator initialized */ } @@ -6841,14 +7148,21 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, */ int get_part_iter_for_interval_via_walking(partition_info *part_info, - bool is_subpart, - uchar *min_value, uchar *max_value, - uint flags, - PARTITION_ITERATOR *part_iter) + bool is_subpart, + uint32 *store_length_array, /* ignored */ + uchar *min_value, uchar *max_value, + uint min_len, uint max_len, /* ignored */ + uint flags, + PARTITION_ITERATOR *part_iter) { Field *field; uint total_parts; partition_iter_func get_next_func; + DBUG_ENTER("get_part_iter_for_interval_via_walking"); + (void)store_length_array; + (void)min_len; + (void)max_len; + if (is_subpart) { field= part_info->subpart_field_array[0]; @@ -6878,7 +7192,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, if (!part_info->get_subpartition_id(part_info, &part_id)) { init_single_partition_iterator(part_id, part_iter); - return 1; /* Ok, iterator initialized */ + DBUG_RETURN(1); /* Ok, iterator initialized */ } } else @@ -6891,10 +7205,10 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, if (!res) { init_single_partition_iterator(part_id, part_iter); - return 1; /* Ok, iterator initialized */ + DBUG_RETURN(1); /* Ok, iterator initialized */ } } - return 0; /* No partitions match */ + DBUG_RETURN(0); /* No partitions match */ } if ((field->real_maybe_null() && @@ -6902,7 +7216,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, (!(flags & NO_MAX_RANGE) && *max_value))) || // X total_parts || n_values > MAX_RANGE_TO_WALK) - return -1; + DBUG_RETURN(-1); part_iter->field_vals.start= part_iter->field_vals.cur= a; part_iter->field_vals.end= b; part_iter->part_info= part_info; part_iter->get_next= get_next_func; - return 1; + DBUG_RETURN(1); } @@ -6976,8 +7290,9 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) DESCRIPTION This implementation of PARTITION_ITERATOR::get_next() is special for - LIST partitioning: it enumerates partition ids in - part_info->list_array[i] where i runs over [min_idx, max_idx] interval. + LIST partitioning: it enumerates partition ids in + part_info->list_array[i] (list_col_array[i] for COLUMN_LIST LIST + partitioning) where i runs over [min_idx, max_idx] interval. The function conforms to partition_iter_func type. RETURN @@ -6999,8 +7314,13 @@ uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter) return NOT_A_PARTITION_ID; } else - return part_iter->part_info->list_array[part_iter-> - part_nums.cur++].partition_id; + { + partition_info *part_info= part_iter->part_info; + uint32 num_part= part_iter->part_nums.cur++; + return part_info->column_list ? + part_info->list_col_array[num_part].partition_id : + part_info->list_array[num_part].partition_id; + } } diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 282e24f1853..7902cc77877 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -173,9 +173,12 @@ typedef struct st_partition_iter SYNOPSIS get_partitions_in_range_iter() part_info Partitioning info - is_subpart + is_subpart + store_length_array Length of fields packed in opt_range_key format min_val Left edge, field value in opt_range_key format. - max_val Right edge, field value in opt_range_key format. + max_val Right edge, field value in opt_range_key format. + min_len Length of minimum value + max_len Length of maximum value flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE, NO_MAX_RANGE. part_iter Iterator structure to be initialized @@ -191,8 +194,9 @@ typedef struct st_partition_iter The set of partitions is returned by initializing an iterator in *part_iter NOTES - There are currently two functions of this type: + There are currently three functions of this type: - get_part_iter_for_interval_via_walking + - get_part_iter_for_interval_cols_via_map - get_part_iter_for_interval_via_mapping RETURN @@ -203,7 +207,9 @@ typedef struct st_partition_iter typedef int (*get_partitions_in_range_iter)(partition_info *part_info, bool is_subpart, + uint32 *store_length_array, uchar *min_val, uchar *max_val, + uint min_len, uint max_len, uint flags, PARTITION_ITERATOR *part_iter); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5c2c351652b..3aef62dfb31 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4869,12 +4869,18 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, /* Partition method*/ switch (part_info->part_type) { case RANGE_PARTITION: - table->field[7]->store(partition_keywords[PKW_RANGE].str, - partition_keywords[PKW_RANGE].length, cs); - break; case LIST_PARTITION: - table->field[7]->store(partition_keywords[PKW_LIST].str, - partition_keywords[PKW_LIST].length, cs); + tmp_res.length(0); + if (part_info->part_type == RANGE_PARTITION) + tmp_res.append(partition_keywords[PKW_RANGE].str, + partition_keywords[PKW_RANGE].length); + else + tmp_res.append(partition_keywords[PKW_LIST].str, + partition_keywords[PKW_LIST].length); + if (part_info->column_list) + tmp_res.append(partition_keywords[PKW_COLUMNS].str, + partition_keywords[PKW_COLUMNS].length); + table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs); break; case HASH_PARTITION: tmp_res.length(0); @@ -6484,7 +6490,7 @@ ST_FIELD_INFO partitions_fields_info[]= (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE}, {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE}, - {"PARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 81d00f46000..fce51c7e3da 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3664,7 +3664,7 @@ bool mysql_create_table_no_lock(THD *thd, ha_resolve_storage_engine_name(part_info->default_engine_type), ha_resolve_storage_engine_name(create_info->db_type))); if (part_info->check_partition_info(thd, &engine_type, file, - create_info, TRUE)) + create_info, FALSE)) goto err; part_info->default_engine_type= engine_type; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4ed9946a334..0e0e3ec6bd3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -515,10 +515,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 169 shift/reduce conflicts. + Currently there are 168 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 169 +%expect 168 /* Comments for TOKENS. @@ -603,6 +603,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token COLLATE_SYM /* SQL-2003-R */ %token COLLATION_SYM /* SQL-2003-N */ %token COLUMNS +%token COLUMN_LIST_SYM %token COLUMN_SYM /* SQL-2003-R */ %token COMMENT_SYM %token COMMITTED_SYM /* SQL-2003-N */ @@ -1156,6 +1157,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_natural_language_mode opt_query_expansion opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt + opt_global %type ulong_num real_ulong_num merge_insert_types @@ -1298,6 +1300,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); view_check_option trigger_tail sp_tail sf_tail udf_tail event_tail install uninstall partition_entry binlog_base64_event init_key_options key_options key_opts key_opt key_using_alg + part_column_list part_column_expr_list part_column_expr_item + part_column_list_value server_def server_options_list server_option definer_opt no_definer definer END_OF_INPUT @@ -1691,12 +1695,12 @@ create: $5->table.str); } } - | CREATE opt_unique_or_fulltext INDEX_SYM ident key_alg ON + | CREATE opt_global opt_unique_or_fulltext INDEX_SYM ident key_alg ON table_ident { LEX *lex=Lex; lex->sql_command= SQLCOM_CREATE_INDEX; - if (!lex->current_select->add_table_to_list(lex->thd, $7, + if (!lex->current_select->add_table_to_list(lex->thd, $8, NULL, TL_OPTION_UPDATING)) MYSQL_YYABORT; @@ -1704,6 +1708,7 @@ create: lex->alter_info.flags= ALTER_ADD_INDEX; lex->col_list.empty(); lex->change=NullS; + lex->global_flag= $2; } '(' key_list ')' key_options { @@ -1714,13 +1719,22 @@ create: my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } - key= new Key($2, $4.str, &lex->key_create_info, 0, + key= new Key($3, $5.str, &lex->key_create_info, 0, lex->col_list); if (key == NULL) MYSQL_YYABORT; lex->alter_info.key_list.push_back(key); lex->col_list.empty(); } + opt_partitioning + { + LEX *lex= Lex; + if (!lex->global_flag && lex->part_info) + { + my_error(ER_GLOBAL_PARTITION_INDEX_ERROR, MYF(0)); + YYABORT; + } + } | CREATE DATABASE opt_if_not_exists ident { Lex->create_info.default_table_charset= NULL; @@ -3802,19 +3816,21 @@ partition: part_type_def: opt_linear KEY_SYM '(' part_field_list ')' { - LEX *lex= Lex; - lex->part_info->list_of_part_fields= TRUE; - lex->part_info->part_type= HASH_PARTITION; + partition_info *part_info= Lex->part_info; + part_info->list_of_part_fields= TRUE; + part_info->part_type= HASH_PARTITION; } | opt_linear HASH_SYM { Lex->part_info->part_type= HASH_PARTITION; } part_func {} - | RANGE_SYM + | RANGE_SYM part_func { Lex->part_info->part_type= RANGE_PARTITION; } - part_func {} - | LIST_SYM + | RANGE_SYM part_column_list + { Lex->part_info->part_type= RANGE_PARTITION; } + | LIST_SYM part_func + { Lex->part_info->part_type= LIST_PARTITION; } + | LIST_SYM part_column_list { Lex->part_info->part_type= LIST_PARTITION; } - part_func {} ; opt_linear: @@ -3836,41 +3852,45 @@ part_field_item_list: part_field_item: ident { - if (Lex->part_info->part_field_list.push_back($1.str)) + partition_info *part_info= Lex->part_info; + part_info->num_columns++; + if (part_info->part_field_list.push_back($1.str)) { mem_alloc_error(1); MYSQL_YYABORT; } + if (part_info->num_columns > MAX_REF_PARTS) + { + my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of partition fields"); + MYSQL_YYABORT; + } } ; +part_column_list: + COLUMN_LIST_SYM '(' part_field_list ')' + { + partition_info *part_info= Lex->part_info; + part_info->column_list= TRUE; + part_info->list_of_part_fields= TRUE; + } + ; + + part_func: '(' remember_name part_func_expr remember_end ')' { - LEX *lex= Lex; - uint expr_len= (uint)($4 - $2) - 1; - lex->part_info->list_of_part_fields= FALSE; - lex->part_info->part_expr= $3; - char *func_string= (char*) sql_memdup($2+1, expr_len); - if (func_string == NULL) - MYSQL_YYABORT; - lex->part_info->part_func_string= func_string; - lex->part_info->part_func_len= expr_len; + if (Lex->part_info->set_part_expr($2+1, $3, $4, FALSE)) + { MYSQL_YYABORT; } } ; sub_part_func: '(' remember_name part_func_expr remember_end ')' { - LEX *lex= Lex; - uint expr_len= (uint)($4 - $2) - 1; - lex->part_info->list_of_subpart_fields= FALSE; - lex->part_info->subpart_expr= $3; - char *func_string= (char*) sql_memdup($2+1, expr_len); - if (func_string == NULL) - MYSQL_YYABORT; - lex->part_info->subpart_func_string= func_string; - lex->part_info->subpart_func_len= expr_len; + if (Lex->part_info->set_part_expr($2+1, $3, $4, TRUE)) + { MYSQL_YYABORT; } } ; @@ -3880,15 +3900,15 @@ opt_no_parts: | PARTITIONS_SYM real_ulong_num { uint no_parts= $2; - LEX *lex= Lex; + partition_info *part_info= Lex->part_info; if (no_parts == 0) { my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions"); MYSQL_YYABORT; } - lex->part_info->no_parts= no_parts; - lex->part_info->use_default_no_partitions= FALSE; + part_info->no_parts= no_parts; + part_info->use_default_no_partitions= FALSE; } ; @@ -3900,9 +3920,9 @@ opt_sub_part: | SUBPARTITION_SYM BY opt_linear KEY_SYM '(' sub_part_field_list ')' { - LEX *lex= Lex; - lex->part_info->subpart_type= HASH_PARTITION; - lex->part_info->list_of_subpart_fields= TRUE; + partition_info *part_info= Lex->part_info; + part_info->subpart_type= HASH_PARTITION; + part_info->list_of_subpart_fields= TRUE; } opt_no_subparts {} ; @@ -3915,11 +3935,18 @@ sub_part_field_list: sub_part_field_item: ident { - if (Lex->part_info->subpart_field_list.push_back($1.str)) + partition_info *part_info= Lex->part_info; + if (part_info->subpart_field_list.push_back($1.str)) { mem_alloc_error(1); MYSQL_YYABORT; } + if (part_info->subpart_field_list.elements > MAX_REF_PARTS) + { + my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of subpartition fields"); + MYSQL_YYABORT; + } } ; @@ -3960,8 +3987,7 @@ part_defs: {} | '(' part_def_list ')' { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; uint count_curr_parts= part_info->partitions.elements; if (part_info->no_parts != 0) { @@ -3988,8 +4014,7 @@ part_def_list: part_definition: PARTITION_SYM { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; partition_element *p_elem= new partition_element(); if (!p_elem || part_info->partitions.push_back(p_elem)) @@ -4013,8 +4038,7 @@ part_definition: part_name: ident { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; partition_element *p_elem= part_info->curr_part_elem; p_elem->partition_name= $1.str; } @@ -4024,15 +4048,16 @@ opt_part_values: /* empty */ { LEX *lex= Lex; + partition_info *part_info= lex->part_info; if (! lex->is_partition_management()) { - if (lex->part_info->part_type == RANGE_PARTITION) + if (part_info->part_type == RANGE_PARTITION) { my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN"); MYSQL_YYABORT; } - if (lex->part_info->part_type == LIST_PARTITION) + if (part_info->part_type == LIST_PARTITION) { my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "LIST", "IN"); @@ -4040,14 +4065,15 @@ opt_part_values: } } else - lex->part_info->part_type= HASH_PARTITION; + part_info->part_type= HASH_PARTITION; } | VALUES LESS_SYM THAN_SYM part_func_max { LEX *lex= Lex; + partition_info *part_info= lex->part_info; if (! lex->is_partition_management()) { - if (Lex->part_info->part_type != RANGE_PARTITION) + if (part_info->part_type != RANGE_PARTITION) { my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN"); @@ -4055,14 +4081,15 @@ opt_part_values: } } else - lex->part_info->part_type= RANGE_PARTITION; + part_info->part_type= RANGE_PARTITION; } | VALUES IN_SYM '(' part_list_func ')' { LEX *lex= Lex; + partition_info *part_info= lex->part_info; if (! lex->is_partition_management()) { - if (Lex->part_info->part_type != LIST_PARTITION) + if (part_info->part_type != LIST_PARTITION) { my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "LIST", "IN"); @@ -4070,36 +4097,139 @@ opt_part_values: } } else - lex->part_info->part_type= LIST_PARTITION; + part_info->part_type= LIST_PARTITION; + } + ; + +part_column_expr_list: + part_column_expr_item {} + | part_column_expr_list ',' part_column_expr_item {} + ; + +part_column_expr_item: + MAX_VALUE_SYM + { + partition_info *part_info= Lex->part_info; + part_column_list_val *col_val; + if (part_info->part_type == LIST_PARTITION) + { + my_parse_error(ER(ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR)); + MYSQL_YYABORT; + } + if (!(col_val= part_info->add_column_value())) + { + MYSQL_YYABORT; + } + col_val->max_value= TRUE; + } + | bit_expr + { + part_column_list_val *col_val; + LEX *lex= Lex; + if (!lex->safe_to_cache_query) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + MYSQL_YYABORT; + } + if (!(col_val= lex->part_info->add_column_value())) + { + MYSQL_YYABORT; + } + col_val->item_expression= $1; + col_val->part_info= NULL; + } + ; + +part_column_list_value: + COLUMN_LIST_SYM + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + uint num_columns; + partition_element *p_elem= part_info->curr_part_elem; + part_column_list_val *col_val_array; + part_elem_value *list_val; + + if (!part_info->column_list && + !lex->is_partition_management()) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + MYSQL_YYABORT; + } + if (!(list_val= + (part_elem_value*)sql_calloc(sizeof(part_elem_value))) || + p_elem->list_val_list.push_back(list_val)) + { + mem_alloc_error(sizeof(part_elem_value)); + MYSQL_YYABORT; + } + if (part_info->num_columns) + num_columns= part_info->num_columns; + else + num_columns= MAX_REF_PARTS; + if (!(col_val_array= + (part_column_list_val*)sql_calloc(num_columns * + sizeof(part_column_list_val)))) + { + mem_alloc_error(num_columns * sizeof(part_elem_value)); + MYSQL_YYABORT; + } + list_val->col_val_array= col_val_array; + part_info->curr_list_val= list_val; + part_info->curr_list_object= 0; + } + '(' part_column_expr_list ')' + { + partition_info *part_info= Lex->part_info; + uint num_columns= part_info->num_columns; + if (num_columns && num_columns != part_info->curr_list_object) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + MYSQL_YYABORT; + } + part_info->num_columns= part_info->curr_list_object; } ; part_func_max: max_value_sym { - LEX *lex= Lex; - if (lex->part_info->defined_max_value) + partition_info *part_info= Lex->part_info; + if (part_info->defined_max_value) { my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR)); MYSQL_YYABORT; } - lex->part_info->defined_max_value= TRUE; - lex->part_info->curr_part_elem->max_value= TRUE; - lex->part_info->curr_part_elem->range_value= LONGLONG_MAX; + if (part_info->column_list) + { + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } + part_info->defined_max_value= TRUE; + part_info->curr_part_elem->max_value= TRUE; + part_info->curr_part_elem->range_value= LONGLONG_MAX; } | part_range_func { - if (Lex->part_info->defined_max_value) + partition_info *part_info= Lex->part_info; + if (part_info->defined_max_value) { my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR)); MYSQL_YYABORT; } - if (Lex->part_info->curr_part_elem->has_null_value) + if (part_info->curr_part_elem->has_null_value) { my_parse_error(ER(ER_NULL_IN_VALUES_LESS_THAN)); MYSQL_YYABORT; } + if (part_info->column_list) + { + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } } + | '(' part_column_list_value ')' + {} ; max_value_sym: @@ -4136,7 +4266,13 @@ part_list_item: mem_alloc_error(sizeof(part_elem_value)); MYSQL_YYABORT; } + if (part_info->column_list) + { + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } } + | part_column_list_value ; part_bit_expr: @@ -4145,6 +4281,7 @@ part_bit_expr: Item *part_expr= $1; THD *thd= YYTHD; LEX *lex= thd->lex; + partition_info *part_info= lex->part_info; Name_resolution_context *context= &lex->current_select->context; TABLE_LIST *save_list= context->table_list; const char *save_where= thd->where; @@ -4181,12 +4318,12 @@ part_bit_expr: value_ptr->unsigned_flag= FALSE; if ((value_ptr->null_value= part_expr->null_value)) { - if (Lex->part_info->curr_part_elem->has_null_value) + if (part_info->curr_part_elem->has_null_value) { my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); MYSQL_YYABORT; } - Lex->part_info->curr_part_elem->has_null_value= TRUE; + part_info->curr_part_elem->has_null_value= TRUE; } else if (part_expr->result_type() != INT_RESULT) { @@ -4200,8 +4337,9 @@ part_bit_expr: opt_sub_partition: /* empty */ { - if (Lex->part_info->no_subparts != 0 && - !Lex->part_info->use_default_subpartitions) + partition_info *part_info= Lex->part_info; + if (part_info->no_subparts != 0 && + !part_info->use_default_subpartitions) { /* We come here when we have defined subpartitions on the first @@ -4213,8 +4351,7 @@ opt_sub_partition: } | '(' sub_part_list ')' { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; if (part_info->no_subparts != 0) { if (part_info->no_subparts != @@ -4245,8 +4382,7 @@ sub_part_list: sub_part_definition: SUBPARTITION_SYM { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; partition_element *curr_part= part_info->current_partition; partition_element *sub_p_elem= new partition_element(curr_part); if (part_info->use_default_subpartitions && @@ -4300,9 +4436,9 @@ opt_part_option: { Lex->part_info->curr_part_elem->tablespace_name= $3.str; } | opt_storage ENGINE_SYM opt_equal storage_engines { - LEX *lex= Lex; - lex->part_info->curr_part_elem->engine_type= $4; - lex->part_info->default_engine_type= $4; + partition_info *part_info= Lex->part_info; + part_info->curr_part_elem->engine_type= $4; + part_info->default_engine_type= $4; } | NODEGROUP_SYM opt_equal real_ulong_num { Lex->part_info->curr_part_elem->nodegroup_id= (uint16) $3; } @@ -4318,6 +4454,11 @@ opt_part_option: { Lex->part_info->curr_part_elem->part_comment= $3.str; } ; +opt_global: + /* empty */ { $$= FALSE;} + | GLOBAL_SYM { $$= TRUE; } + ; + /* End of partition parser part */ @@ -5786,8 +5927,8 @@ reorg_parts_rule: } INTO '(' part_def_list ')' { - LEX *lex= Lex; - lex->part_info->no_parts= lex->part_info->partitions.elements; + partition_info *part_info= Lex->part_info; + part_info->no_parts= part_info->partitions.elements; } ; @@ -11529,7 +11670,6 @@ keyword_sp: | MAX_SIZE_SYM {} | MAX_UPDATES_PER_HOUR {} | MAX_USER_CONNECTIONS_SYM {} - | MAX_VALUE_SYM {} | MEDIUM_SYM {} | MEMORY_SYM {} | MERGE_SYM {} From 3b29941f5df7ba95685da159344bc2632c12f1ac Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 15 Sep 2009 17:27:10 +0200 Subject: [PATCH 009/274] Forgot to add result files for WL#3352 new test cases --- mysql-test/r/partition_column.result | 213 +++++++++++++++++++++ mysql-test/r/partition_column_prune.result | 66 +++++++ 2 files changed, 279 insertions(+) create mode 100644 mysql-test/r/partition_column.result create mode 100644 mysql-test/r/partition_column_prune.result diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result new file mode 100644 index 00000000000..5c6464b271d --- /dev/null +++ b/mysql-test/r/partition_column.result @@ -0,0 +1,213 @@ +drop table if exists t1; +create table t1 (a int, b char(10), c varchar(25), d datetime) +partition by range column_list(a,b,c,d) +subpartition by hash (to_seconds(d)) +subpartitions 4 +( partition p0 values less than (column_list(1, NULL, MAXVALUE, NULL)), +partition p1 values less than (column_list(1, 'a', MAXVALUE, TO_DAYS('1999-01-01'))), +partition p2 values less than (column_list(1, 'a', MAXVALUE, MAXVALUE)), +partition p3 values less than (column_list(1, MAXVALUE, MAXVALUE, MAXVALUE))); +drop table t1; +create table t1 (a int, b char(10), c varchar(5), d int) +partition by range column_list(a,b,c) +subpartition by key (c,d) +subpartitions 3 +( partition p0 values less than (column_list(1,'abc','abc')), +partition p1 values less than (column_list(2,'abc','abc')), +partition p2 values less than (column_list(3,'abc','abc')), +partition p3 values less than (column_list(4,'abc','abc'))); +insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); +insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); +insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3); +insert into t1 values (1,'d','e',1),(2,'d','e',2),(3,'d','e',3); +select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) OR +(a = 1 AND b >= 'a' AND (c = 'c' OR (c = 'd' AND d = 2)))); +a b c d +1 a b 1 +1 b c 1 +drop table t1; +create table t1 (a int, b varchar(2), c int) +partition by range column_list (a, b, c) +(partition p0 values less than (column_list(1, 'A', 1)), +partition p1 values less than (column_list(1, 'B', 1))); +insert into t1 values (1, 'A', 1); +explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 system NULL NULL NULL NULL 1 +select * from t1 where a = 1 AND b <= 'A' and c = 1; +a b c +1 A 1 +drop table t1; +create table t1 (a char, b char, c char) +partition by list column_list(a) +( partition p0 values in (column_list('a'))); +insert into t1 (a) values ('a'); +select * from t1 where a = 'a'; +a b c +a NULL NULL +drop table t1; +create table t1 (d timestamp) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), +partition p1 values less than (column_list('2040-01-01'))); +ERROR HY000: Partition column values of incorrect type +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(null, 10))); +drop table t1; +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), +partition p1 values less than (column_list('2009-01-01'))); +drop table t1; +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('1999-01-01')), +partition p1 values less than (column_list('2000-01-01'))); +drop table t1; +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), +partition p1 values less than (column_list('3000-01-01'))); +drop table t1; +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p2 values less than (column_list(99,99)), +partition p1 values less than (column_list(99,999))); +insert into t1 values (99,998); +select * from t1 where b = 998; +a b +99 998 +drop table t1; +create table t1 as select to_seconds(null) as to_seconds; +select data_type from information_schema.columns +where column_name='to_seconds'; +data_type +int +drop table t1; +create table t1 (a int, b int) +partition by list column_list(a,b) +(partition p0 values in (column_list(maxvalue,maxvalue))); +ERROR 42000: Cannot use MAXVALUE as value in List partitioning near 'maxvalue,maxvalue)))' at line 3 +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(maxvalue,maxvalue))); +drop table t1; +create table t1 (a int) +partition by list column_list(a) +(partition p0 values in (column_list(0))); +select partition_method from information_schema.partitions where table_name='t1'; +partition_method +LIST COLUMN_LIST +drop table t1; +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list('H23456')), +partition p1 values less than (column_list('M23456'))); +insert into t1 values ('F23456'); +select * from t1; +a +F23456 +drop table t1; +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list(H23456)), +partition p1 values less than (column_list(M23456))); +ERROR 42S22: Unknown column 'H23456' in 'field list' +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list(23456)), +partition p1 values less than (column_list(23456))); +ERROR HY000: VALUES LESS THAN value must be strictly increasing for each partition +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (10)); +ERROR 42000: Inconsistency in usage of column lists for partitioning near '))' at line 3 +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(1,1,1)); +ERROR HY000: Inconsistency in usage of column lists for partitioning +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(1, NULL)), +partition p1 values less than (column_list(2, maxvalue)), +partition p2 values less than (column_list(3, 3)), +partition p3 values less than (column_list(10, NULL))); +insert into t1 values (10,0); +ERROR HY000: Table has no partition for value from column_list +insert into t1 values (0,1),(1,1),(2,1),(3,1),(3,4),(4,9),(9,1); +select * from t1; +a b +0 1 +1 1 +2 1 +3 1 +3 4 +4 9 +9 1 +alter table t1 +partition by range column_list(b,a) +(partition p0 values less than (column_list(1,2)), +partition p1 values less than (column_list(3,3)), +partition p2 values less than (column_list(9,5))); +explain partitions select * from t1 where b < 2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 7 Using where +select * from t1 where b < 2; +a b +0 1 +1 1 +2 1 +3 1 +9 1 +explain partitions select * from t1 where b < 4; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1,p2 ALL NULL NULL NULL NULL 7 Using where +select * from t1 where b < 4; +a b +0 1 +1 1 +2 1 +3 1 +9 1 +alter table t1 reorganize partition p1 into +(partition p11 values less than (column_list(2,2)), +partition p12 values less than (column_list(3,3))); +alter table t1 reorganize partition p0 into +(partition p01 values less than (column_list(0,3)), +partition p02 values less than (column_list(1,1))); +ERROR HY000: Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range +alter table t1 reorganize partition p2 into +(partition p2 values less than(column_list(9,6,1))); +ERROR HY000: Inconsistency in usage of column lists for partitioning +alter table t1 reorganize partition p2 into +(partition p2 values less than (10)); +ERROR HY000: Inconsistency in usage of column lists for partitioning +alter table t1 reorganize partition p2 into +(partition p21 values less than (column_list(4,7)), +partition p22 values less than (column_list(9,5))); +explain partitions select * from t1 where b < 4; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p11,p12,p21 ALL NULL NULL NULL NULL 7 Using where +select * from t1 where b < 4; +a b +0 1 +1 1 +2 1 +3 1 +9 1 +drop table t1; +create table t1 (a int, b int) +partition by list column_list(a,b) +subpartition by hash (b) +subpartitions 2 +(partition p0 values in (column_list(0,0), column_list(1,1)), +partition p1 values in (column_list(1000,1000))); +insert into t1 values (1000,1000); +drop table t1; +create table t1 (a char, b char, c char) +partition by range column_list(a,b,c) +( partition p0 values less than (column_list('a','b','c'))); +alter table t1 add partition +(partition p1 values less than (column_list('b','c','d'))); +drop table t1; diff --git a/mysql-test/r/partition_column_prune.result b/mysql-test/r/partition_column_prune.result new file mode 100644 index 00000000000..8f7a8f85d05 --- /dev/null +++ b/mysql-test/r/partition_column_prune.result @@ -0,0 +1,66 @@ +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +create table t1 (a char, b char, c char) +partition by range column_list(a,b,c) +( partition p0 values less than (column_list('a','b','c'))); +insert into t1 values ('a', NULL, 'd'); +explain partitions select * from t1 where a = 'a' AND c = 'd'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 system NULL NULL NULL NULL 1 +select * from t1 where a = 'a' AND c = 'd'; +a b c +a NULL d +drop table t1; +create table t1 (a int not null) partition by range column_list(a) ( +partition p0 values less than (column_list(10)), +partition p1 values less than (column_list(20)), +partition p2 values less than (column_list(30)), +partition p3 values less than (column_list(40)), +partition p4 values less than (column_list(50)), +partition p5 values less than (column_list(60)), +partition p6 values less than (column_list(70)) +); +insert into t1 values (5),(15),(25),(35),(45),(55),(65); +insert into t1 values (5),(15),(25),(35),(45),(55),(65); +create table t2 (a int not null) partition by range(a) ( +partition p0 values less than (10), +partition p1 values less than (20), +partition p2 values less than (30), +partition p3 values less than (40), +partition p4 values less than (50), +partition p5 values less than (60), +partition p6 values less than (70) +); +insert into t2 values (5),(15),(25),(35),(45),(55),(65); +insert into t2 values (5),(15),(25),(35),(45),(55),(65); +explain partitions select * from t1 where a > 35 and a < 45; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p3,p4 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t2 where a > 35 and a < 45; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p3,p4 ALL NULL NULL NULL NULL 4 Using where +drop table t1, t2; +create table t1 (a int not null, b int not null ) +partition by range column_list(a,b) ( +partition p01 values less than (column_list(2,10)), +partition p02 values less than (column_list(2,20)), +partition p03 values less than (column_list(2,30)), +partition p11 values less than (column_list(4,10)), +partition p12 values less than (column_list(4,20)), +partition p13 values less than (column_list(4,30)), +partition p21 values less than (column_list(6,10)), +partition p22 values less than (column_list(6,20)), +partition p23 values less than (column_list(6,30)) +); +insert into t1 values (2,5), (2,15), (2,25), +(4,5), (4,15), (4,25), (6,5), (6,15), (6,25); +insert into t1 select * from t1; +explain partitions select * from t1 where a=2; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p01,p02,p03,p11 ALL NULL NULL NULL NULL 13 Using where +explain partitions select * from t1 where a=4; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p11,p12,p13,p21 ALL NULL NULL NULL NULL 16 Using where +explain partitions select * from t1 where a=2 and b < 22; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p01,p02,p03 ALL NULL NULL NULL NULL 16 Using where +drop table t1; From 4336ca40729a86c9c6f5d48a52589ab05f22158d Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Thu, 17 Sep 2009 03:23:05 -0600 Subject: [PATCH 010/274] fixed tree name --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index ddb2588bbc1..197a0ef0dc0 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.4.3-next-mr" +tree_name = "mysql-5.4.3-trunk-signal" From 8249fd6eef37dcbfc7f37359998c41e96aabee03 Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Wed, 23 Sep 2009 11:43:43 +0200 Subject: [PATCH 011/274] BUG#29288: myisam transactions replicated to a transactional slave leaves slave unstable Problem: when replicating from non-transactional to transactional engine with autocommit off, no BEGIN/COMMIT is written to the binlog. When the slave replicates, it will start a transaction that never ends. Fix: Force autocommit=on on slave by always replicating autocommit=1 from the master. --- .../rpl_ndb/r/rpl_ndb_mixed_tables.result | 286 ++++++++++++++ .../rpl_ndb/t/rpl_ndb_mixed_tables-master.opt | 1 + .../rpl_ndb/t/rpl_ndb_mixed_tables-slave.opt | 1 + .../suite/rpl_ndb/t/rpl_ndb_mixed_tables.test | 349 ++++++++++++++++++ sql/log_event.cc | 28 +- 5 files changed, 659 insertions(+), 6 deletions(-) create mode 100644 mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_tables.result create mode 100644 mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables-master.opt create mode 100644 mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables-slave.opt create mode 100644 mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables.test diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_tables.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_tables.result new file mode 100644 index 00000000000..92fda774da5 --- /dev/null +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_tables.result @@ -0,0 +1,286 @@ +==== Initialization ==== +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +---- setup master ---- +CREATE TABLE myisam_innodb (a INT) ENGINE=MYISAM; +CREATE TABLE innodb_myisam (a INT) ENGINE=INNODB; +CREATE TABLE myisam_ndb (a INT) ENGINE=MYISAM; +CREATE TABLE ndb_myisam (a INT) ENGINE=NDB; +CREATE TABLE innodb_ndb (a INT) ENGINE=INNODB; +CREATE TABLE ndb_innodb (a INT) ENGINE=NDB; +SHOW CREATE TABLE myisam_innodb; +Table Create Table +myisam_innodb CREATE TABLE `myisam_innodb` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE innodb_myisam; +Table Create Table +innodb_myisam CREATE TABLE `innodb_myisam` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW CREATE TABLE myisam_ndb; +Table Create Table +myisam_ndb CREATE TABLE `myisam_ndb` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE ndb_myisam; +Table Create Table +ndb_myisam CREATE TABLE `ndb_myisam` ( + `a` int(11) DEFAULT NULL +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE innodb_ndb; +Table Create Table +innodb_ndb CREATE TABLE `innodb_ndb` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW CREATE TABLE ndb_innodb; +Table Create Table +ndb_innodb CREATE TABLE `ndb_innodb` ( + `a` int(11) DEFAULT NULL +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +---- setup slave with different engines ---- +DROP TABLE myisam_innodb, innodb_myisam; +DROP TABLE myisam_ndb, ndb_myisam; +DROP TABLE innodb_ndb, ndb_innodb; +CREATE TABLE myisam_innodb (a INT) ENGINE=INNODB; +CREATE TABLE innodb_myisam (a INT) ENGINE=MYISAM; +CREATE TABLE myisam_ndb (a INT) ENGINE=NDB; +CREATE TABLE ndb_myisam (a INT) ENGINE=MYISAM; +CREATE TABLE innodb_ndb (a INT) ENGINE=NDB; +CREATE TABLE ndb_innodb (a INT) ENGINE=INNODB; +SHOW CREATE TABLE myisam_innodb; +Table Create Table +myisam_innodb CREATE TABLE `myisam_innodb` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW CREATE TABLE innodb_myisam; +Table Create Table +innodb_myisam CREATE TABLE `innodb_myisam` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE myisam_ndb; +Table Create Table +myisam_ndb CREATE TABLE `myisam_ndb` ( + `a` int(11) DEFAULT NULL +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE ndb_myisam; +Table Create Table +ndb_myisam CREATE TABLE `ndb_myisam` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE innodb_ndb; +Table Create Table +innodb_ndb CREATE TABLE `innodb_ndb` ( + `a` int(11) DEFAULT NULL +) ENGINE=ndbcluster DEFAULT CHARSET=latin1 +SHOW CREATE TABLE ndb_innodb; +Table Create Table +ndb_innodb CREATE TABLE `ndb_innodb` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +==== AUTOCOMMIT=0, transactions ==== +---- COMMIT ---- +SET AUTOCOMMIT = 0; +BEGIN; +INSERT INTO myisam_innodb VALUES (1); +INSERT INTO myisam_innodb VALUES (2); +COMMIT; +BEGIN; +INSERT INTO innodb_myisam VALUES (3); +INSERT INTO innodb_myisam VALUES (4); +COMMIT; +BEGIN; +INSERT INTO myisam_ndb VALUES (5); +INSERT INTO myisam_ndb VALUES (6); +COMMIT; +BEGIN; +INSERT INTO ndb_myisam VALUES (7); +INSERT INTO ndb_myisam VALUES (8); +COMMIT; +BEGIN; +INSERT INTO ndb_innodb VALUES (9); +INSERT INTO ndb_innodb VALUES (10); +COMMIT; +BEGIN; +INSERT INTO innodb_ndb VALUES (11); +INSERT INTO innodb_ndb VALUES (12); +COMMIT; +---- ROLLBACK ---- +BEGIN; +INSERT INTO myisam_innodb VALUES (13); +INSERT INTO myisam_innodb VALUES (14); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +BEGIN; +INSERT INTO innodb_myisam VALUES (15); +INSERT INTO innodb_myisam VALUES (16); +ROLLBACK; +BEGIN; +INSERT INTO myisam_ndb VALUES (17); +INSERT INTO myisam_ndb VALUES (18); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +BEGIN; +INSERT INTO ndb_myisam VALUES (19); +INSERT INTO ndb_myisam VALUES (20); +ROLLBACK; +BEGIN; +INSERT INTO ndb_innodb VALUES (21); +INSERT INTO ndb_innodb VALUES (22); +ROLLBACK; +BEGIN; +INSERT INTO innodb_ndb VALUES (23); +INSERT INTO innodb_ndb VALUES (24); +ROLLBACK; +==== AUTOCOMMIT=1, transactions ==== +---- COMMIT ---- +SET AUTOCOMMIT = 1; +BEGIN; +INSERT INTO myisam_innodb VALUES (25); +INSERT INTO myisam_innodb VALUES (26); +COMMIT; +BEGIN; +INSERT INTO innodb_myisam VALUES (27); +INSERT INTO innodb_myisam VALUES (28); +COMMIT; +BEGIN; +INSERT INTO myisam_ndb VALUES (29); +INSERT INTO myisam_ndb VALUES (30); +COMMIT; +BEGIN; +INSERT INTO ndb_myisam VALUES (31); +INSERT INTO ndb_myisam VALUES (32); +COMMIT; +BEGIN; +INSERT INTO ndb_innodb VALUES (33); +INSERT INTO ndb_innodb VALUES (34); +COMMIT; +BEGIN; +INSERT INTO innodb_ndb VALUES (35); +INSERT INTO innodb_ndb VALUES (36); +COMMIT; +---- ROLLBACK ---- +BEGIN; +INSERT INTO myisam_innodb VALUES (37); +INSERT INTO myisam_innodb VALUES (38); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +BEGIN; +INSERT INTO innodb_myisam VALUES (39); +INSERT INTO innodb_myisam VALUES (40); +ROLLBACK; +BEGIN; +INSERT INTO myisam_ndb VALUES (41); +INSERT INTO myisam_ndb VALUES (42); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +BEGIN; +INSERT INTO ndb_myisam VALUES (43); +INSERT INTO ndb_myisam VALUES (44); +ROLLBACK; +BEGIN; +INSERT INTO ndb_innodb VALUES (45); +INSERT INTO ndb_innodb VALUES (46); +ROLLBACK; +BEGIN; +INSERT INTO innodb_ndb VALUES (47); +INSERT INTO innodb_ndb VALUES (48); +ROLLBACK; +==== AUTOCOMMIT=1, single statements ==== +INSERT INTO myisam_innodb VALUES (49); +INSERT INTO myisam_innodb VALUES (50); +INSERT INTO innodb_myisam VALUES (51); +INSERT INTO innodb_myisam VALUES (52); +INSERT INTO myisam_ndb VALUES (53); +INSERT INTO myisam_ndb VALUES (54); +INSERT INTO ndb_myisam VALUES (55); +INSERT INTO ndb_myisam VALUES (56); +INSERT INTO ndb_innodb VALUES (57); +INSERT INTO ndb_innodb VALUES (58); +INSERT INTO innodb_ndb VALUES (59); +INSERT INTO innodb_ndb VALUES (60); +==== AUTOCOMMIT=0, single statements, myisam on master ==== +SET AUTOCOMMIT = 0; +INSERT INTO myisam_innodb VALUES (61); +INSERT INTO myisam_innodb VALUES (62); +INSERT INTO myisam_ndb VALUES (63); +INSERT INTO myisam_ndb VALUES (64); +==== Show results ==== +SELECT * FROM myisam_innodb ORDER BY a; +a +1 +2 +13 +14 +25 +26 +37 +38 +49 +50 +61 +62 +SELECT * FROM innodb_myisam ORDER BY a; +a +3 +4 +27 +28 +51 +52 +SELECT * FROM myisam_ndb ORDER BY a; +a +5 +6 +17 +18 +29 +30 +41 +42 +53 +54 +63 +64 +SELECT * FROM ndb_myisam ORDER BY a; +a +7 +8 +31 +32 +55 +56 +SELECT * FROM innodb_ndb ORDER BY a; +a +11 +12 +35 +36 +59 +60 +SELECT * FROM ndb_innodb ORDER BY a; +a +9 +10 +33 +34 +57 +58 +Comparing tables master:test.myisam_innodb and slave:test.myisam_innodb +Comparing tables master:test.innodb_myisam and slave:test.innodb_myisam +Comparing tables master:test.myisam_ndb and slave:test.myisam_ndb +Comparing tables master:test.ndb_myisam and slave:test.ndb_myisam +Comparing tables master:test.innodb_ndb and slave:test.innodb_ndb +Comparing tables master:test.ndb_innodb and slave:test.ndb_innodb +==== Clean up ==== +drop table myisam_innodb, innodb_myisam; +drop table myisam_ndb, ndb_myisam; +drop table innodb_ndb, ndb_innodb; diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables-master.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables-master.opt new file mode 100644 index 00000000000..b74354b22e1 --- /dev/null +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables-master.opt @@ -0,0 +1 @@ +--innodb --ndbcluster diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables-slave.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables-slave.opt new file mode 100644 index 00000000000..bbb86b2991b --- /dev/null +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables-slave.opt @@ -0,0 +1 @@ +--innodb --ndbcluster --replicate-ignore-table=mysql.ndb_apply_status diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables.test new file mode 100644 index 00000000000..7d7cd5770cf --- /dev/null +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables.test @@ -0,0 +1,349 @@ +# ==== Purpose ==== +# +# Test replication of transactions on tables which have different +# engines on master and slave. This tests all combinations of innodb, +# myisam, and ndb. +# +# ==== Method ==== +# +# Set up six tables, each being innodb, myisam, or innodb on master, +# and another of innodb, myisam, or innodb on slave. For each table, +# do the following: +# +# - committed and rollback'ed transactions, with autocommit on and +# off +# - non-transactions with autocommit on +# - non-transactions with autocommit off, where the master table is +# myisam. +# +# Note: we are running the slave with +# --replicate-ignore-table=mysql.ndb_apply_status . See BUG#34557 for +# explanation. +# +# ==== Related bugs ==== +# +# BUG#26395: if crash during autocommit update to transactional table on master, slave fails +# BUG#29288: myisam transactions replicated to a transactional slave leaves slave unstable +# BUG#34557: Row-based replication from ndb to non-ndb gives error on slave +# BUG#34600: Rolled-back punch transactions not replicated correctly +# +# ==== Todo ==== +# +# We should eventually try transactions touching two tables which are +# of different engines on the same server (so that we try, e.g. punch +# transactions; cf BUG#34600). However, that will make the test much +# bigger (9 master-slave engine combinations [myisam->myisam, +# myisam->ndb, etc]. To try all combinations of one or more such +# tables means 2^9-1=511 transactions. We need to multiplied by 5 +# since we want to test committed/rollback'ed transactions +# with/without AUTOCOMMIT, as well as non-transactions with +# autocommit). We'd have to write a script to produce the test case. + + +--echo ==== Initialization ==== + +--source include/have_ndb.inc +--source include/have_innodb.inc +--source include/ndb_master-slave.inc + +--echo ---- setup master ---- + +CREATE TABLE myisam_innodb (a INT) ENGINE=MYISAM; +CREATE TABLE innodb_myisam (a INT) ENGINE=INNODB; +CREATE TABLE myisam_ndb (a INT) ENGINE=MYISAM; +CREATE TABLE ndb_myisam (a INT) ENGINE=NDB; +CREATE TABLE innodb_ndb (a INT) ENGINE=INNODB; +CREATE TABLE ndb_innodb (a INT) ENGINE=NDB; + +SHOW CREATE TABLE myisam_innodb; +SHOW CREATE TABLE innodb_myisam; +SHOW CREATE TABLE myisam_ndb; +SHOW CREATE TABLE ndb_myisam; +SHOW CREATE TABLE innodb_ndb; +SHOW CREATE TABLE ndb_innodb; + +--echo ---- setup slave with different engines ---- + +sync_slave_with_master; + +DROP TABLE myisam_innodb, innodb_myisam; +DROP TABLE myisam_ndb, ndb_myisam; +DROP TABLE innodb_ndb, ndb_innodb; + +CREATE TABLE myisam_innodb (a INT) ENGINE=INNODB; +CREATE TABLE innodb_myisam (a INT) ENGINE=MYISAM; +CREATE TABLE myisam_ndb (a INT) ENGINE=NDB; +CREATE TABLE ndb_myisam (a INT) ENGINE=MYISAM; +CREATE TABLE innodb_ndb (a INT) ENGINE=NDB; +CREATE TABLE ndb_innodb (a INT) ENGINE=INNODB; + +SHOW CREATE TABLE myisam_innodb; +SHOW CREATE TABLE innodb_myisam; +SHOW CREATE TABLE myisam_ndb; +SHOW CREATE TABLE ndb_myisam; +SHOW CREATE TABLE innodb_ndb; +SHOW CREATE TABLE ndb_innodb; + +connection master; + + +--echo ==== AUTOCOMMIT=0, transactions ==== + +--echo ---- COMMIT ---- + +SET AUTOCOMMIT = 0; + +BEGIN; +INSERT INTO myisam_innodb VALUES (1); +INSERT INTO myisam_innodb VALUES (2); +COMMIT; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO innodb_myisam VALUES (3); +INSERT INTO innodb_myisam VALUES (4); +COMMIT; +sync_slave_with_master; +connection master; + +BEGIN; +INSERT INTO myisam_ndb VALUES (5); +INSERT INTO myisam_ndb VALUES (6); +COMMIT; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO ndb_myisam VALUES (7); +INSERT INTO ndb_myisam VALUES (8); +COMMIT; +sync_slave_with_master; +connection master; + +BEGIN; +INSERT INTO ndb_innodb VALUES (9); +INSERT INTO ndb_innodb VALUES (10); +COMMIT; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO innodb_ndb VALUES (11); +INSERT INTO innodb_ndb VALUES (12); +COMMIT; +sync_slave_with_master; +connection master; + +--echo ---- ROLLBACK ---- + +BEGIN; +INSERT INTO myisam_innodb VALUES (13); +INSERT INTO myisam_innodb VALUES (14); +ROLLBACK; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO innodb_myisam VALUES (15); +INSERT INTO innodb_myisam VALUES (16); +ROLLBACK; +sync_slave_with_master; +connection master; + +BEGIN; +INSERT INTO myisam_ndb VALUES (17); +INSERT INTO myisam_ndb VALUES (18); +ROLLBACK; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO ndb_myisam VALUES (19); +INSERT INTO ndb_myisam VALUES (20); +ROLLBACK; +sync_slave_with_master; +connection master; + +BEGIN; +INSERT INTO ndb_innodb VALUES (21); +INSERT INTO ndb_innodb VALUES (22); +ROLLBACK; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO innodb_ndb VALUES (23); +INSERT INTO innodb_ndb VALUES (24); +ROLLBACK; +sync_slave_with_master; +connection master; + + +--echo ==== AUTOCOMMIT=1, transactions ==== + +--echo ---- COMMIT ---- + +SET AUTOCOMMIT = 1; + +BEGIN; +INSERT INTO myisam_innodb VALUES (25); +INSERT INTO myisam_innodb VALUES (26); +COMMIT; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO innodb_myisam VALUES (27); +INSERT INTO innodb_myisam VALUES (28); +COMMIT; +sync_slave_with_master; +connection master; + +BEGIN; +INSERT INTO myisam_ndb VALUES (29); +INSERT INTO myisam_ndb VALUES (30); +COMMIT; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO ndb_myisam VALUES (31); +INSERT INTO ndb_myisam VALUES (32); +COMMIT; +sync_slave_with_master; +connection master; + +BEGIN; +INSERT INTO ndb_innodb VALUES (33); +INSERT INTO ndb_innodb VALUES (34); +COMMIT; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO innodb_ndb VALUES (35); +INSERT INTO innodb_ndb VALUES (36); +COMMIT; +sync_slave_with_master; +connection master; + +--echo ---- ROLLBACK ---- + +BEGIN; +INSERT INTO myisam_innodb VALUES (37); +INSERT INTO myisam_innodb VALUES (38); +ROLLBACK; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO innodb_myisam VALUES (39); +INSERT INTO innodb_myisam VALUES (40); +ROLLBACK; +sync_slave_with_master; +connection master; + +BEGIN; +INSERT INTO myisam_ndb VALUES (41); +INSERT INTO myisam_ndb VALUES (42); +ROLLBACK; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO ndb_myisam VALUES (43); +INSERT INTO ndb_myisam VALUES (44); +ROLLBACK; +sync_slave_with_master; +connection master; + +BEGIN; +INSERT INTO ndb_innodb VALUES (45); +INSERT INTO ndb_innodb VALUES (46); +ROLLBACK; +sync_slave_with_master; +connection master; +BEGIN; +INSERT INTO innodb_ndb VALUES (47); +INSERT INTO innodb_ndb VALUES (48); +ROLLBACK; +sync_slave_with_master; +connection master; + + +--echo ==== AUTOCOMMIT=1, single statements ==== + +INSERT INTO myisam_innodb VALUES (49); +INSERT INTO myisam_innodb VALUES (50); +sync_slave_with_master; +connection master; +INSERT INTO innodb_myisam VALUES (51); +INSERT INTO innodb_myisam VALUES (52); +sync_slave_with_master; +connection master; + +INSERT INTO myisam_ndb VALUES (53); +INSERT INTO myisam_ndb VALUES (54); +sync_slave_with_master; +connection master; +INSERT INTO ndb_myisam VALUES (55); +INSERT INTO ndb_myisam VALUES (56); +sync_slave_with_master; +connection master; + +INSERT INTO ndb_innodb VALUES (57); +INSERT INTO ndb_innodb VALUES (58); +sync_slave_with_master; +connection master; +INSERT INTO innodb_ndb VALUES (59); +INSERT INTO innodb_ndb VALUES (60); +sync_slave_with_master; +connection master; + + +--echo ==== AUTOCOMMIT=0, single statements, myisam on master ==== + +SET AUTOCOMMIT = 0; + +# This tests BUG#29288. +INSERT INTO myisam_innodb VALUES (61); +INSERT INTO myisam_innodb VALUES (62); +sync_slave_with_master; +connection master; + +INSERT INTO myisam_ndb VALUES (63); +INSERT INTO myisam_ndb VALUES (64); +sync_slave_with_master; +connection master; + + +--echo ==== Show results ==== + +SELECT * FROM myisam_innodb ORDER BY a; +SELECT * FROM innodb_myisam ORDER BY a; +SELECT * FROM myisam_ndb ORDER BY a; +SELECT * FROM ndb_myisam ORDER BY a; +SELECT * FROM innodb_ndb ORDER BY a; +SELECT * FROM ndb_innodb ORDER BY a; + +let $diff_table_1=master:test.myisam_innodb; +let $diff_table_2=slave:test.myisam_innodb; +source include/diff_tables.inc; + +let $diff_table_1=master:test.innodb_myisam; +let $diff_table_2=slave:test.innodb_myisam; +source include/diff_tables.inc; + +let $diff_table_1=master:test.myisam_ndb; +let $diff_table_2=slave:test.myisam_ndb; +source include/diff_tables.inc; + +let $diff_table_1=master:test.ndb_myisam; +let $diff_table_2=slave:test.ndb_myisam; +source include/diff_tables.inc; + +let $diff_table_1=master:test.innodb_ndb; +let $diff_table_2=slave:test.innodb_ndb; +source include/diff_tables.inc; + +let $diff_table_1=master:test.ndb_innodb; +let $diff_table_2=slave:test.ndb_innodb; +source include/diff_tables.inc; + + +--echo ==== Clean up ==== + +drop table myisam_innodb, innodb_myisam; +drop table myisam_ndb, ndb_myisam; +drop table innodb_ndb, ndb_innodb; +sync_slave_with_master; diff --git a/sql/log_event.cc b/sql/log_event.cc index 0cda724b698..fb6a5230fda 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2389,13 +2389,29 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, charset_database_number= thd_arg->variables.collation_database->number; /* - If we don't use flags2 for anything else than options contained in - thd_arg->options, it would be more efficient to flags2=thd_arg->options - (OPTIONS_WRITTEN_TO_BIN_LOG would be used only at reading time). - But it's likely that we don't want to use 32 bits for 3 bits; in the future - we will probably want to reclaim the 29 bits. So we need the &. + We only replicate over the bits of flags2 that we need: the rest + are masked out by "& OPTIONS_WRITTEN_TO_BINLOG". + + We also force AUTOCOMMIT=1. Rationale (cf. BUG#29288): After + fixing BUG#26395, we always write BEGIN and COMMIT around all + transactions (even single statements in autocommit mode). This is + so that replication from non-transactional to transactional table + and error recovery from XA to non-XA table should work as + expected. The BEGIN/COMMIT are added in log.cc. However, there is + one exception: MyISAM bypasses log.cc and writes directly to the + binlog. So if autocommit is off, master has MyISAM, and slave has + a transactional engine, then the slave will just see one long + never-ending transaction. The only way to bypass explicit + BEGIN/COMMIT in the binlog is by using a non-transactional table. + So setting AUTOCOMMIT=1 will make this work as expected. + + Note: explicitly replicate AUTOCOMMIT=1 from master. We do not + assume AUTOCOMMIT=1 on slave; the slave still reads the state of + the autocommit flag as written by the master to the binlog. This + behavior may change after WL#4162 has been implemented. */ - flags2= (uint32) (thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG); + flags2= (uint32) (thd_arg->options & + (OPTIONS_WRITTEN_TO_BIN_LOG & ~OPTION_NOT_AUTOCOMMIT)); DBUG_ASSERT(thd_arg->variables.character_set_client->number < 256*256); DBUG_ASSERT(thd_arg->variables.collation_connection->number < 256*256); DBUG_ASSERT(thd_arg->variables.collation_server->number < 256*256); From 7947948c5225b5e48dfeb18a17f0c170620bfc89 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Wed, 23 Sep 2009 14:12:43 +0400 Subject: [PATCH 012/274] Update default.conf. --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index efd9210319e..771201a109b 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.4.5-next-mr-bugfixing" +tree_name = "mysql-5.4.5-next-mr" From 124e830125a2964a60d01cf9df68ddc9caa70a0d Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Wed, 23 Sep 2009 13:20:48 +0200 Subject: [PATCH 013/274] Bug #37221: SET AUTOCOMMIT=1 does not commit binary log When setting AUTOCOMMIT=1 after starting a transaction, the binary log did not commit the outstanding transaction. The reason was that the binary log commit function saw the values of the new settings, deciding that there were nothing to commit. Fixed the problem by moving the implicit commit to before the thread option flags were changed, so that the binary log sees the old values of the flags instead of the values they will take after the statement. mysql-test/extra/binlog_tests/implicit.test: New test file to check implicit commits both inside and outside transactions. mysql-test/suite/binlog/t/binlog_implicit_commit.test: Test for implicit commit of SET AUTOCOMMIT and LOCK/UNLOCK TABLES. sql/set_var.cc: Adding code to commit pending transaction before changing option flags. --- mysql-test/extra/binlog_tests/implicit.test | 28 ++ .../binlog/r/binlog_implicit_commit.result | 345 ++++++++++++++++++ .../binlog/t/binlog_implicit_commit.test | 63 ++++ sql/set_var.cc | 11 +- 4 files changed, 445 insertions(+), 2 deletions(-) create mode 100644 mysql-test/extra/binlog_tests/implicit.test create mode 100644 mysql-test/suite/binlog/r/binlog_implicit_commit.result create mode 100644 mysql-test/suite/binlog/t/binlog_implicit_commit.test diff --git a/mysql-test/extra/binlog_tests/implicit.test b/mysql-test/extra/binlog_tests/implicit.test new file mode 100644 index 00000000000..84d80288d36 --- /dev/null +++ b/mysql-test/extra/binlog_tests/implicit.test @@ -0,0 +1,28 @@ +# First part: outside a transaction +RESET MASTER; +eval $prepare; + +INSERT INTO t1 VALUES (1); +source include/show_binlog_events.inc; +eval $statement; +source include/show_binlog_events.inc; +if (`select '$cleanup' != ''`) { + eval $cleanup; +} + +# Second part: inside a transaction +RESET MASTER; +eval $prepare; +BEGIN; +INSERT INTO t1 VALUES (2); +source include/show_binlog_events.inc; +eval $statement; +source include/show_binlog_events.inc; +INSERT INTO t1 VALUES (3); +source include/show_binlog_events.inc; +COMMIT; +source include/show_binlog_events.inc; +if (`select '$cleanup' != ''`) { + eval $cleanup; +} + diff --git a/mysql-test/suite/binlog/r/binlog_implicit_commit.result b/mysql-test/suite/binlog/r/binlog_implicit_commit.result new file mode 100644 index 00000000000..ea43b31bde9 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_implicit_commit.result @@ -0,0 +1,345 @@ +CREATE TABLE t1 (id INT) ENGINE = InnoDB; +SET BINLOG_FORMAT = STATEMENT; +RESET MASTER; +SET AUTOCOMMIT = 0; +INSERT INTO t1 VALUES (1); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 0; +BEGIN; +INSERT INTO t1 VALUES (2); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Xid # # COMMIT /* XID */ +INSERT INTO t1 VALUES (3); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 1; +INSERT INTO t1 VALUES (1); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Xid # # COMMIT /* XID */ +SET AUTOCOMMIT = 1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 1; +BEGIN; +INSERT INTO t1 VALUES (2); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +INSERT INTO t1 VALUES (3); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 0; +INSERT INTO t1 VALUES (1); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 0; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 0; +BEGIN; +INSERT INTO t1 VALUES (2); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 0; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +INSERT INTO t1 VALUES (3); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 1; +INSERT INTO t1 VALUES (1); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Xid # # COMMIT /* XID */ +SET AUTOCOMMIT = 0; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 1; +BEGIN; +INSERT INTO t1 VALUES (2); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 0; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +INSERT INTO t1 VALUES (3); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +SET BINLOG_FORMAT = ROW; +RESET MASTER; +SET AUTOCOMMIT = 0; +INSERT INTO t1 VALUES (1); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 0; +BEGIN; +INSERT INTO t1 VALUES (2); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +INSERT INTO t1 VALUES (3); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 1; +INSERT INTO t1 VALUES (1); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +SET AUTOCOMMIT = 1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 1; +BEGIN; +INSERT INTO t1 VALUES (2); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 1; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +INSERT INTO t1 VALUES (3); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 0; +INSERT INTO t1 VALUES (1); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 0; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 0; +BEGIN; +INSERT INTO t1 VALUES (2); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 0; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +INSERT INTO t1 VALUES (3); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 1; +INSERT INTO t1 VALUES (1); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +SET AUTOCOMMIT = 0; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 1; +BEGIN; +INSERT INTO t1 VALUES (2); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +SET AUTOCOMMIT = 0; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +INSERT INTO t1 VALUES (3); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +RESET MASTER; +SET AUTOCOMMIT = 0; +INSERT INTO t1 VALUES (1); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +LOCK TABLES t1 WRITE; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +INSERT INTO t1 VALUES (2); +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +UNLOCK TABLES; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +COMMIT; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/t/binlog_implicit_commit.test b/mysql-test/suite/binlog/t/binlog_implicit_commit.test new file mode 100644 index 00000000000..a682ab95e3d --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_implicit_commit.test @@ -0,0 +1,63 @@ +# The purpose of this test is to test that setting autocommit does a +# commit of outstanding transactions and nothing is left pending in +# the transaction cache. + +source include/have_log_bin.inc; +source include/have_innodb.inc; + +# We need a transactional engine, so let's use InnoDB +CREATE TABLE t1 (id INT) ENGINE = InnoDB; + +# Testing SET AUTOCOMMIT +SET BINLOG_FORMAT = STATEMENT; + +let $cleanup = COMMIT; + +let $prepare = SET AUTOCOMMIT = 0; +let $statement = SET AUTOCOMMIT = 1; +source extra/binlog_tests/implicit.test; + +let $prepare = SET AUTOCOMMIT = 1; +let $statement = SET AUTOCOMMIT = 1; +source extra/binlog_tests/implicit.test; + +let $prepare = SET AUTOCOMMIT = 0; +let $statement = SET AUTOCOMMIT = 0; +source extra/binlog_tests/implicit.test; + +let $prepare = SET AUTOCOMMIT = 1; +let $statement = SET AUTOCOMMIT = 0; +source extra/binlog_tests/implicit.test; + +SET BINLOG_FORMAT = ROW; +let $prepare = SET AUTOCOMMIT = 0; +let $statement = SET AUTOCOMMIT = 1; +source extra/binlog_tests/implicit.test; + +let $prepare = SET AUTOCOMMIT = 1; +let $statement = SET AUTOCOMMIT = 1; +source extra/binlog_tests/implicit.test; + +let $prepare = SET AUTOCOMMIT = 0; +let $statement = SET AUTOCOMMIT = 0; +source extra/binlog_tests/implicit.test; + +let $prepare = SET AUTOCOMMIT = 1; +let $statement = SET AUTOCOMMIT = 0; +source extra/binlog_tests/implicit.test; + +RESET MASTER; +SET AUTOCOMMIT = 0; +INSERT INTO t1 VALUES (1); +source include/show_binlog_events.inc; +LOCK TABLES t1 WRITE; +source include/show_binlog_events.inc; +INSERT INTO t1 VALUES (2); +source include/show_binlog_events.inc; +UNLOCK TABLES; +source include/show_binlog_events.inc; +COMMIT; +source include/show_binlog_events.inc; + +# Cleaning up +DROP TABLE t1; diff --git a/sql/set_var.cc b/sql/set_var.cc index 0b89333ce03..5025356230c 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3054,6 +3054,15 @@ static bool set_option_autocommit(THD *thd, set_var *var) ulonglong org_options= thd->options; + /* + If we are setting AUTOCOMMIT=1 and it was not already 1, then we + need to commit any outstanding transactions. + */ + if (var->save_result.ulong_value != 0 && + (thd->options & OPTION_NOT_AUTOCOMMIT) && + ha_commit(thd)) + return 1; + if (var->save_result.ulong_value != 0) thd->options&= ~((sys_var_thd_bit*) var->var)->bit_flag; else @@ -3067,8 +3076,6 @@ static bool set_option_autocommit(THD *thd, set_var *var) thd->options&= ~(ulonglong) (OPTION_BEGIN | OPTION_KEEP_LOG); thd->transaction.all.modified_non_trans_table= FALSE; thd->server_status|= SERVER_STATUS_AUTOCOMMIT; - if (ha_commit(thd)) - return 1; } else { From b0220ff9ff6fbc9fc65a9b04f25e337951edd259 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Wed, 23 Sep 2009 18:02:39 +0400 Subject: [PATCH 014/274] Ignore a new symbolic link. --- .bzrignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.bzrignore b/.bzrignore index 6c6a43dacab..0dd59e5cee8 100644 --- a/.bzrignore +++ b/.bzrignore @@ -3064,3 +3064,4 @@ sql/share/spanish sql/share/swedish sql/share/ukrainian libmysqld/examples/mysqltest.cc +libmysqld/sql_signal.cc From d47710c8dccd295428fa7547720f4a5d7311c413 Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Wed, 23 Sep 2009 23:32:31 +0200 Subject: [PATCH 015/274] WL#5016: Fix header file include guards Adding header include file guards to files that are missing such. --- client/my_readline.h | 5 +++++ client/sql_string.h | 5 +++++ include/atomic/gcc_builtins.h | 5 +++++ include/atomic/nolock.h | 4 ++++ include/atomic/rwlock.h | 4 ++++ include/atomic/x86-gcc.h | 4 ++++ include/config-win.h | 5 +++++ include/errmsg.h | 4 ++++ include/help_end.h | 4 ++++ include/help_start.h | 4 ++++ include/my_aes.h | 5 +++++ include/my_atomic.h | 4 ++++ include/my_bit.h | 5 +++++ include/my_libwrap.h | 4 ++++ include/my_md5.h | 5 +++++ include/my_no_pthread.h | 8 +++++--- include/my_uctype.h | 4 ++++ include/myisampack.h | 4 ++++ include/mysql_embed.h | 4 ++++ include/rijndael.h | 5 +++++ include/sha1.h | 5 +++++ include/sql_common.h | 4 ++++ include/sslopt-case.h | 4 ++++ include/sslopt-longopts.h | 4 ++++ include/sslopt-vars.h | 4 ++++ libmysql/client_settings.h | 6 ++++++ mysys/my_handler_errors.h | 3 +++ mysys/my_static.h | 5 +++++ sql/authors.h | 5 +++++ sql/client_settings.h | 6 ++++++ sql/contributors.h | 5 +++++ sql/field.h | 5 +++++ sql/gstream.h | 5 +++++ sql/ha_ndbcluster.h | 5 +++++ sql/ha_ndbcluster_binlog.h | 5 +++++ sql/ha_ndbcluster_cond.h | 5 +++++ sql/ha_ndbcluster_tables.h | 5 +++++ sql/ha_partition.h | 5 +++++ sql/handler.h | 4 ++++ sql/item.h | 5 +++++ sql/item_cmpfunc.h | 5 +++++ sql/item_func.h | 4 ++++ sql/item_geofunc.h | 4 ++++ sql/item_row.h | 5 +++++ sql/item_strfunc.h | 4 ++++ sql/item_subselect.h | 5 ++++- sql/item_sum.h | 5 +++++ sql/item_timefunc.h | 5 +++++ sql/item_xmlfunc.h | 4 ++++ sql/lex.h | 5 +++++ sql/message.h | 7 +++++++ sql/mysqld_suffix.h | 4 ++++ sql/nt_servc.h | 5 +++++ sql/partition_element.h | 5 +++++ sql/partition_info.h | 5 +++++ sql/procedure.h | 5 +++++ sql/protocol.h | 4 ++++ sql/repl_failsafe.h | 4 ++++ sql/scheduler.h | 5 +++++ sql/set_var.h | 5 +++++ sql/sql_acl.h | 4 ++++ sql/sql_analyse.h | 5 +++++ sql/sql_array.h | 4 ++++ sql/sql_class.h | 4 ++++ sql/sql_crypt.h | 5 +++++ sql/sql_lex.h | 4 ++++ sql/sql_map.h | 5 +++++ sql/sql_partition.h | 4 ++++ sql/sql_repl.h | 4 ++++ sql/sql_select.h | 4 ++++ sql/sql_servers.h | 5 +++++ sql/sql_sort.h | 5 +++++ sql/sql_string.h | 5 +++++ sql/sql_trigger.h | 4 ++++ sql/sql_udf.h | 4 ++++ sql/sql_view.h | 4 ++++ sql/structs.h | 5 +++++ sql/table.h | 4 ++++ sql/tzfile.h | 5 +++++ sql/tztime.h | 4 ++++ sql/unireg.h | 5 +++-- strings/strings-not-used.h | 4 ++++ vio/vio_priv.h | 4 ++++ 83 files changed, 377 insertions(+), 6 deletions(-) diff --git a/client/my_readline.h b/client/my_readline.h index 62ad19bece9..08cff565819 100644 --- a/client/my_readline.h +++ b/client/my_readline.h @@ -1,3 +1,6 @@ +#ifndef CLIENT_MY_READLINE_INCLUDED +#define CLIENT_MY_READLINE_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -31,3 +34,5 @@ extern LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file); extern LINE_BUFFER *batch_readline_command(LINE_BUFFER *buffer, char * str); extern char *batch_readline(LINE_BUFFER *buffer, bool *truncated); extern void batch_readline_end(LINE_BUFFER *buffer); + +#endif /* CLIENT_MY_READLINE_INCLUDED */ diff --git a/client/sql_string.h b/client/sql_string.h index da19c1ccfe5..0e6d6da4476 100644 --- a/client/sql_string.h +++ b/client/sql_string.h @@ -1,3 +1,6 @@ +#ifndef CLIENT_SQL_STRING_INCLUDED +#define CLIENT_SQL_STRING_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -353,3 +356,5 @@ public: return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->str_length); } }; + +#endif /* CLIENT_SQL_STRING_INCLUDED */ diff --git a/include/atomic/gcc_builtins.h b/include/atomic/gcc_builtins.h index 509701b30a5..01ebc38707e 100644 --- a/include/atomic/gcc_builtins.h +++ b/include/atomic/gcc_builtins.h @@ -1,3 +1,6 @@ +#ifndef ATOMIC_GCC_BUILTINS_INCLUDED +#define ATOMIC_GCC_BUILTINS_INCLUDED + /* Copyright (C) 2008 MySQL AB This program is free software; you can redistribute it and/or modify @@ -31,3 +34,5 @@ #define make_atomic_store_body(S) \ (void) __sync_lock_test_and_set(a, v); #endif + +#endif /* ATOMIC_GCC_BUILTINS_INCLUDED */ diff --git a/include/atomic/nolock.h b/include/atomic/nolock.h index 10ac17884b6..2c652fd52c1 100644 --- a/include/atomic/nolock.h +++ b/include/atomic/nolock.h @@ -1,3 +1,6 @@ +#ifndef ATOMIC_NOLOCK_INCLUDED +#define ATOMIC_NOLOCK_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -42,3 +45,4 @@ typedef struct { } my_atomic_rwlock_t; #endif +#endif /* ATOMIC_NOLOCK_INCLUDED */ diff --git a/include/atomic/rwlock.h b/include/atomic/rwlock.h index 18b77e93d80..0ff4d16c545 100644 --- a/include/atomic/rwlock.h +++ b/include/atomic/rwlock.h @@ -1,3 +1,6 @@ +#ifndef ATOMIC_RWLOCK_INCLUDED +#define ATOMIC_RWLOCK_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -46,3 +49,4 @@ typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t; #define make_atomic_load_body(S) ret= *a; #define make_atomic_store_body(S) *a= v; +#endif /* ATOMIC_RWLOCK_INCLUDED */ diff --git a/include/atomic/x86-gcc.h b/include/atomic/x86-gcc.h index d79dadbf05e..d8afa5bfbf1 100644 --- a/include/atomic/x86-gcc.h +++ b/include/atomic/x86-gcc.h @@ -1,3 +1,6 @@ +#ifndef ATOMIC_X86_GCC_INCLUDED +#define ATOMIC_X86_GCC_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -56,3 +59,4 @@ asm volatile ("; xchg %0, %1;" : "+m" (*a) : "r" (v)) #endif +#endif /* ATOMIC_X86_GCC_INCLUDED */ diff --git a/include/config-win.h b/include/config-win.h index af4915440b1..c00e26866b9 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -1,3 +1,6 @@ +#ifndef CONFIG_WIN_INCLUDED +#define CONFIG_WIN_INCLUDED + /* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify @@ -410,3 +413,5 @@ inline ulonglong double2ulonglong(double d) #define HAVE_UCA_COLLATIONS 1 #define HAVE_BOOL 1 + +#endif /* CONFIG_WIN_INCLUDED */ diff --git a/include/errmsg.h b/include/errmsg.h index a6d8c770de8..5754e99ba5e 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -1,3 +1,6 @@ +#ifndef ERRMSG_INCLUDED +#define ERRMSG_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -100,3 +103,4 @@ extern const char *client_errors[]; /* Error messages */ #define CR_ERROR_LAST /*Copy last error nr:*/ 2057 /* Add error numbers before CR_ERROR_LAST and change it accordingly. */ +#endif /* ERRMSG_INCLUDED */ diff --git a/include/help_end.h b/include/help_end.h index 4426cb80bce..92953efe35a 100644 --- a/include/help_end.h +++ b/include/help_end.h @@ -1,3 +1,6 @@ +#ifndef HELP_END_INCLUDED +#define HELP_END_INCLUDED + /* Copyright (C) 2004-2005 MySQL AB This program is free software; you can redistribute it and/or modify @@ -20,3 +23,4 @@ #undef fputc #undef putchar #endif +#endif /* HELP_END_INCLUDED */ diff --git a/include/help_start.h b/include/help_start.h index 3ae20eea7d7..414f7ec93a0 100644 --- a/include/help_start.h +++ b/include/help_start.h @@ -1,3 +1,6 @@ +#ifndef HELP_START_INCLUDED +#define HELP_START_INCLUDED + /* Copyright (C) 2004-2005 MySQL AB This program is free software; you can redistribute it and/or modify @@ -22,3 +25,4 @@ #define fputc(s,f) consoleprintf("%c", s) #define putchar(s) consoleprintf("%c", s) #endif +#endif /* HELP_START_INCLUDED */ diff --git a/include/my_aes.h b/include/my_aes.h index 1bbdf5663ea..2e2a66b4968 100644 --- a/include/my_aes.h +++ b/include/my_aes.h @@ -1,3 +1,6 @@ +#ifndef MY_AES_INCLUDED +#define MY_AES_INCLUDED + /* Copyright (C) 2002 MySQL AB This program is free software; you can redistribute it and/or modify @@ -63,3 +66,5 @@ int my_aes_decrypt(const char *source, int source_length, char *dest, int my_aes_get_size(int source_length); C_MODE_END + +#endif /* MY_AES_INCLUDED */ diff --git a/include/my_atomic.h b/include/my_atomic.h index ed439e5fe87..8481b8e6d5a 100644 --- a/include/my_atomic.h +++ b/include/my_atomic.h @@ -1,3 +1,6 @@ +#ifndef MY_ATOMIC_INCLUDED +#define MY_ATOMIC_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -140,3 +143,4 @@ extern int my_atomic_initialize(); #endif +#endif /* MY_ATOMIC_INCLUDED */ diff --git a/include/my_bit.h b/include/my_bit.h index 2e464e89049..5cbf4f8b83e 100644 --- a/include/my_bit.h +++ b/include/my_bit.h @@ -1,3 +1,6 @@ +#ifndef MY_BIT_INCLUDED +#define MY_BIT_INCLUDED + /* Some useful bit functions */ @@ -107,3 +110,5 @@ extern uint my_count_bits(ulonglong v); extern uint my_count_bits_ushort(ushort v); #endif /* HAVE_INLINE */ C_MODE_END + +#endif /* MY_BIT_INCLUDED */ diff --git a/include/my_libwrap.h b/include/my_libwrap.h index 9a8579475fb..8235c00d8f3 100644 --- a/include/my_libwrap.h +++ b/include/my_libwrap.h @@ -1,3 +1,6 @@ +#ifndef MY_LIBWRAP_INCLUDED +#define MY_LIBWRAP_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -25,3 +28,4 @@ extern int my_hosts_access(struct request_info *req); extern char *my_eval_client(struct request_info *req); #endif /* HAVE_LIBWRAP */ +#endif /* MY_LIBWRAP_INCLUDED */ diff --git a/include/my_md5.h b/include/my_md5.h index 6458f27c5cc..782bef8a27a 100644 --- a/include/my_md5.h +++ b/include/my_md5.h @@ -1,3 +1,6 @@ +#ifndef MY_MD5_INCLUDED +#define MY_MD5_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -52,3 +55,5 @@ do { \ my_MD5Update (&ctx, buf, len); \ my_MD5Final (digest, &ctx); \ } while (0) + +#endif /* MY_MD__INCLUDED */ diff --git a/include/my_no_pthread.h b/include/my_no_pthread.h index b11dbff42f0..31c1bf2b6ac 100644 --- a/include/my_no_pthread.h +++ b/include/my_no_pthread.h @@ -1,3 +1,6 @@ +#ifndef MY_NO_PTHREAD_INCLUDED +#define MY_NO_PTHREAD_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -14,9 +17,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#if !defined(_my_no_pthread_h) && !defined(THREAD) -#define _my_no_pthread_h - +#ifndef THREAD /* This block is to access some thread-related type definitions @@ -48,3 +49,4 @@ #define rwlock_destroy(A) #endif +#endif /* MY_NO_PTHREAD_INCLUDED */ diff --git a/include/my_uctype.h b/include/my_uctype.h index 9aaf478810c..580eb646e11 100644 --- a/include/my_uctype.h +++ b/include/my_uctype.h @@ -1,3 +1,6 @@ +#ifndef MY_UCTYPE_INCLUDED +#define MY_UCTYPE_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -1477,3 +1480,4 @@ MY_UNI_CTYPE my_uni_ctype[256]={ }; +#endif /* MY_UCTYPE_INCLUDED */ diff --git a/include/myisampack.h b/include/myisampack.h index 7d4871bd1cb..ecf35520a88 100644 --- a/include/myisampack.h +++ b/include/myisampack.h @@ -1,3 +1,6 @@ +#ifndef MYISAMPACK_INCLUDED +#define MYISAMPACK_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -236,3 +239,4 @@ mi_int4store(((T) + 4), A); }} #define mi_sizekorr(T) mi_uint4korr((uchar*) (T) + 4) #endif +#endif /* MYISAMPACK_INCLUDED */ diff --git a/include/mysql_embed.h b/include/mysql_embed.h index 4a7fd3ef63c..0e5a360585e 100644 --- a/include/mysql_embed.h +++ b/include/mysql_embed.h @@ -1,3 +1,6 @@ +#ifndef MYSQL_EMBED_INCLUDED +#define MYSQL_EMBED_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -28,3 +31,4 @@ #define DONT_USE_RAID #endif /* EMBEDDED_LIBRARY */ +#endif /* MYSQL_EMBED_INCLUDED */ diff --git a/include/rijndael.h b/include/rijndael.h index 89963a85c99..71df1c48dbf 100644 --- a/include/rijndael.h +++ b/include/rijndael.h @@ -1,3 +1,6 @@ +#ifndef RIJNDAEL_INCLUDED +#define RIJNDAEL_INCLUDED + /* Copyright (C) 2002 MySQL AB This program is free software; you can redistribute it and/or modify @@ -39,3 +42,5 @@ void rijndaelEncrypt(const uint32 rk[/*4*(Nr + 1)*/], int Nr, const uint8 pt[16], uint8 ct[16]); void rijndaelDecrypt(const uint32 rk[/*4*(Nr + 1)*/], int Nr, const uint8 ct[16], uint8 pt[16]); + +#endif /* RIJNDAEL_INCLUDED */ diff --git a/include/sha1.h b/include/sha1.h index e476456a9bd..5b4dc5d46ed 100644 --- a/include/sha1.h +++ b/include/sha1.h @@ -1,3 +1,6 @@ +#ifndef SHA1_INCLUDED +#define SHA1_INCLUDED + /* Copyright (C) 2002, 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -64,3 +67,5 @@ int mysql_sha1_input(SHA1_CONTEXT*, const uint8 *, unsigned int); int mysql_sha1_result(SHA1_CONTEXT* , uint8 Message_Digest[SHA1_HASH_SIZE]); C_MODE_END + +#endif /* SHA__INCLUDED */ diff --git a/include/sql_common.h b/include/sql_common.h index 9e43d076ba9..5fd8778d62b 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -1,3 +1,6 @@ +#ifndef SQL_COMMON_INCLUDED +#define SQL_COMMON_INCLUDED + /* Copyright (C) 2003-2004, 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -48,3 +51,4 @@ void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate); #define protocol_41(A) ((A)->server_capabilities & CLIENT_PROTOCOL_41) +#endif /* SQL_COMMON_INCLUDED */ diff --git a/include/sslopt-case.h b/include/sslopt-case.h index adb9a28503b..ce46cf65cc9 100644 --- a/include/sslopt-case.h +++ b/include/sslopt-case.h @@ -1,3 +1,6 @@ +#ifndef SSLOPT_CASE_INCLUDED +#define SSLOPT_CASE_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -26,3 +29,4 @@ opt_use_ssl= 1; break; #endif +#endif /* SSLOPT_CASE_INCLUDED */ diff --git a/include/sslopt-longopts.h b/include/sslopt-longopts.h index c76b5dcd252..eae1424238b 100644 --- a/include/sslopt-longopts.h +++ b/include/sslopt-longopts.h @@ -1,3 +1,6 @@ +#ifndef SSLOPT_LONGOPTS_INCLUDED +#define SSLOPT_LONGOPTS_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -43,3 +46,4 @@ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif #endif /* HAVE_OPENSSL */ +#endif /* SSLOPT_LONGOPTS_INCLUDED */ diff --git a/include/sslopt-vars.h b/include/sslopt-vars.h index 3369f870db2..4493fbc59ab 100644 --- a/include/sslopt-vars.h +++ b/include/sslopt-vars.h @@ -1,3 +1,6 @@ +#ifndef SSLOPT_VARS_INCLUDED +#define SSLOPT_VARS_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -29,3 +32,4 @@ SSL_STATIC char *opt_ssl_key = 0; SSL_STATIC my_bool opt_ssl_verify_server_cert= 0; #endif #endif +#endif /* SSLOPT_VARS_INCLUDED */ diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h index f87e625771f..1fd8619a746 100644 --- a/libmysql/client_settings.h +++ b/libmysql/client_settings.h @@ -13,6 +13,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef CLIENT_SETTINGS_INCLUDED +#define CLIENT_SETTINGS_INCLUDED +#else +#error You have already included an client_settings.h and it should not be included twice +#endif /* CLIENT_SETTINGS_INCLUDED */ + extern uint mysql_port; extern char * mysql_unix_port; diff --git a/mysys/my_handler_errors.h b/mysys/my_handler_errors.h index c239cabb168..e4e62f47fed 100644 --- a/mysys/my_handler_errors.h +++ b/mysys/my_handler_errors.h @@ -1,3 +1,5 @@ +#ifndef MYSYS_MY_HANDLER_ERRORS_INCLUDED +#define MYSYS_MY_HANDLER_ERRORS_INCLUDED /* Errors a handler can give you @@ -66,3 +68,4 @@ static const char *handler_error_messages[]= "Too many active concurrent transactions" }; +#endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */ diff --git a/mysys/my_static.h b/mysys/my_static.h index 90168b099a8..c336115bc35 100644 --- a/mysys/my_static.h +++ b/mysys/my_static.h @@ -1,3 +1,6 @@ +#ifndef MYSYS_MY_STATIC_INCLUDED +#define MYSYS_MY_STATIC_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -72,3 +75,5 @@ extern ulonglong query_performance_frequency, query_performance_offset; extern sigset_t my_signals; /* signals blocked by mf_brkhant */ #endif C_MODE_END + +#endif /* MYSYS_MY_STATIC_INCLUDED */ diff --git a/sql/authors.h b/sql/authors.h index dfe3b143e2f..90cdae9c0a0 100644 --- a/sql/authors.h +++ b/sql/authors.h @@ -1,3 +1,6 @@ +#ifndef AUTHORS_INCLUDED +#define AUTHORS_INCLUDED + /* Copyright (C) 2005-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -150,3 +153,5 @@ struct show_table_authors_st show_table_authors[]= { "SHA1(), AES_ENCRYPT(), AES_DECRYPT(), bug fixing" }, {NULL, NULL, NULL} }; + +#endif /* AUTHORS_INCLUDED */ diff --git a/sql/client_settings.h b/sql/client_settings.h index 4f06c15a29e..fd50bfdbb88 100644 --- a/sql/client_settings.h +++ b/sql/client_settings.h @@ -14,6 +14,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef CLIENT_SETTINGS_INCLUDED +#define CLIENT_SETTINGS_INCLUDED +#else +#error You have already included an client_settings.h and it should not be included twice +#endif /* CLIENT_SETTINGS_INCLUDED */ + #include #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \ diff --git a/sql/contributors.h b/sql/contributors.h index 87001e29d88..6cf8bb88e3b 100644 --- a/sql/contributors.h +++ b/sql/contributors.h @@ -1,3 +1,6 @@ +#ifndef CONTRIBUTORS_INCLUDED +#define CONTRIBUTORS_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -37,3 +40,5 @@ struct show_table_contributors_st show_table_contributors[]= { {"Mark Shuttleworth", "London, UK.", "EFF contribution for UC2006 Auction"}, {NULL, NULL, NULL} }; + +#endif /* CONTRIBUTORS_INCLUDED */ diff --git a/sql/field.h b/sql/field.h index a9299256f88..36569428ee0 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1,3 +1,6 @@ +#ifndef FIELD_INCLUDED +#define FIELD_INCLUDED + /* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify @@ -2180,3 +2183,5 @@ int set_field_to_null_with_conversions(Field *field, bool no_conversions); #define f_no_default(x) (x & FIELDFLAG_NO_DEFAULT) #define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) #define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) + +#endif /* FIELD_INCLUDED */ diff --git a/sql/gstream.h b/sql/gstream.h index 1ef90ad5bf0..ea7158ee1a3 100644 --- a/sql/gstream.h +++ b/sql/gstream.h @@ -1,3 +1,6 @@ +#ifndef GSTREAM_INCLUDED +#define GSTREAM_INCLUDED + /* Copyright (C) 2000-2004 MySQL AB This program is free software; you can redistribute it and/or modify @@ -73,3 +76,5 @@ protected: char *m_err_msg; CHARSET_INFO *m_charset; }; + +#endif /* GSTREAM_INCLUDED */ diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index a17323d3fd6..662655c42b9 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -1,3 +1,6 @@ +#ifndef HA_NDBCLUSTER_INCLUDED +#define HA_NDBCLUSTER_INCLUDED + /* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -581,3 +584,5 @@ static const int ndbcluster_hton_name_length=sizeof(ndbcluster_hton_name)-1; extern int ndbcluster_terminating; extern int ndb_util_thread_running; extern pthread_cond_t COND_ndb_util_ready; + +#endif /* HA_NDBCLUSTER_INCLUDED */ diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h index 1cad643e5ec..d80dfe9ee74 100644 --- a/sql/ha_ndbcluster_binlog.h +++ b/sql/ha_ndbcluster_binlog.h @@ -1,3 +1,6 @@ +#ifndef HA_NDBCLUSTER_BINLOG_INCLUDED +#define HA_NDBCLUSTER_BINLOG_INCLUDED + /* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -225,3 +228,5 @@ set_thd_ndb(THD *thd, Thd_ndb *thd_ndb) { thd_set_ha_data(thd, ndbcluster_hton, thd_ndb); } Ndb* check_ndb_in_thd(THD* thd); + +#endif /* HA_NDBCLUSTER_BINLOG_INCLUDED */ diff --git a/sql/ha_ndbcluster_cond.h b/sql/ha_ndbcluster_cond.h index 4401a93c9e1..4ccc7e062ec 100644 --- a/sql/ha_ndbcluster_cond.h +++ b/sql/ha_ndbcluster_cond.h @@ -1,3 +1,6 @@ +#ifndef HA_NDBCLUSTER_COND_INCLUDED +#define HA_NDBCLUSTER_COND_INCLUDED + /* Copyright (C) 2000-2007 MySQL AB This program is free software; you can redistribute it and/or modify @@ -486,3 +489,5 @@ private: Ndb_cond_stack *m_cond_stack; }; + +#endif /* HA_NDBCLUSTER_COND_INCLUDED */ diff --git a/sql/ha_ndbcluster_tables.h b/sql/ha_ndbcluster_tables.h index c6bc8f577f8..ba2e8ec251b 100644 --- a/sql/ha_ndbcluster_tables.h +++ b/sql/ha_ndbcluster_tables.h @@ -1,3 +1,6 @@ +#ifndef HA_NDBCLUSTER_TABLES_INCLUDED +#define HA_NDBCLUSTER_TABLES_INCLUDED + /* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -21,3 +24,5 @@ #define OLD_NDB_APPLY_TABLE "apply_status" #define NDB_SCHEMA_TABLE "ndb_schema" #define OLD_NDB_SCHEMA_TABLE "schema" + +#endif /* HA_NDBCLUSTER_TABLES_INCLUDED */ diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 8a81a759e2a..804db028953 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1,3 +1,6 @@ +#ifndef HA_PARTITION_INCLUDED +#define HA_PARTITION_INCLUDED + /* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify @@ -1090,3 +1093,5 @@ public: virtual void append_create_info(String *packet) */ }; + +#endif /* HA_PARTITION_INCLUDED */ diff --git a/sql/handler.h b/sql/handler.h index f759239d66e..a281aaa0ad7 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1,3 +1,6 @@ +#ifndef HANDLER_INCLUDED +#define HANDLER_INCLUDED + /* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify @@ -2064,3 +2067,4 @@ int ha_binlog_end(THD *thd); #define ha_binlog_wait(a) do {} while (0) #define ha_binlog_end(a) do {} while (0) #endif +#endif /* HANDLER_INCLUDED */ diff --git a/sql/item.h b/sql/item.h index a2cff3ab3a9..b44e84f4b15 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1,3 +1,6 @@ +#ifndef ITEM_INCLUDED +#define ITEM_INCLUDED + /* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify @@ -3126,3 +3129,5 @@ extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); extern int stored_field_cmp_to_item(Field *field, Item *item); + +#endif /* ITEM_INCLUDED */ diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index c2227fa04e0..3462bed94a2 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1,3 +1,6 @@ +#ifndef ITEM_CMPFUNC_INCLUDED +#define ITEM_CMPFUNC_INCLUDED + /* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -1721,3 +1724,5 @@ inline Item *and_conds(Item *a, Item *b) } Item *and_expressions(Item *a, Item *b, Item **org_item); + +#endif /* ITEM_CMPFUNC_INCLUDED */ diff --git a/sql/item_func.h b/sql/item_func.h index fdbbff89e60..628878bcaed 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1,3 +1,6 @@ +#ifndef ITEM_FUNC_INCLUDED +#define ITEM_FUNC_INCLUDED + /* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify @@ -1718,3 +1721,4 @@ public: bool check_partition_func_processor(uchar *int_arg) {return FALSE;} }; +#endif /* ITEM_FUNC_INCLUDED */ diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index edbe104e307..9a55ea7d5b1 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -1,3 +1,6 @@ +#ifndef ITEM_GEOFUNC_INCLUDED +#define ITEM_GEOFUNC_INCLUDED + /* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -386,3 +389,4 @@ public: #endif +#endif /* ITEM_GEOFUNC_INCLUDED */ diff --git a/sql/item_row.h b/sql/item_row.h index 67441f49603..7c08c5888e0 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -1,3 +1,6 @@ +#ifndef ITEM_ROW_INCLUDED +#define ITEM_ROW_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -77,3 +80,5 @@ public: bool null_inside() { return with_null; }; void bring_value(); }; + +#endif /* ITEM_ROW_INCLUDED */ diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 2cdb45100ae..fc70b04ca68 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -1,3 +1,6 @@ +#ifndef ITEM_STRFUNC_INCLUDED +#define ITEM_STRFUNC_INCLUDED + /* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -842,3 +845,4 @@ public: String *val_str(String *); }; +#endif /* ITEM_STRFUNC_INCLUDED */ diff --git a/sql/item_subselect.h b/sql/item_subselect.h index d4aa621c083..ea59521aab1 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -1,3 +1,6 @@ +#ifndef ITEM_SUBSELECT_INCLUDED +#define ITEM_SUBSELECT_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -579,4 +582,4 @@ inline bool Item_subselect::is_uncacheable() const return engine->uncacheable(); } - +#endif /* ITEM_SUBSELECT_INCLUDED */ diff --git a/sql/item_sum.h b/sql/item_sum.h index d991327d847..993ec1597b4 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1,3 +1,6 @@ +#ifndef ITEM_SUM_INCLUDED +#define ITEM_SUM_INCLUDED + /* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -1279,3 +1282,5 @@ public: virtual bool change_context_processor(uchar *cntx) { context= (Name_resolution_context *)cntx; return FALSE; } }; + +#endif /* ITEM_SUM_INCLUDED */ diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 9e3c2e8c89f..7f1b2ed3a53 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -1,3 +1,6 @@ +#ifndef ITEM_TIMEFUNC_INCLUDED +#define ITEM_TIMEFUNC_INCLUDED + /* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -1026,3 +1029,5 @@ public: const char *func_name() const { return "last_day"; } bool get_date(MYSQL_TIME *res, uint fuzzy_date); }; + +#endif /* ITEM_TIMEFUNC_INCLUDED */ diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h index dadbb5ccf42..6373bde0aab 100644 --- a/sql/item_xmlfunc.h +++ b/sql/item_xmlfunc.h @@ -1,3 +1,6 @@ +#ifndef ITEM_XMLFUNC_INCLUDED +#define ITEM_XMLFUNC_INCLUDED + /* Copyright (C) 2000-2005 MySQL AB This program is free software; you can redistribute it and/or modify @@ -61,3 +64,4 @@ public: String *val_str(String *); }; +#endif /* ITEM_XMLFUNC_INCLUDED */ diff --git a/sql/lex.h b/sql/lex.h index 0a85824f6f7..b199a79350b 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -1,3 +1,6 @@ +#ifndef LEX_INCLUDED +#define LEX_INCLUDED + /* Copyright (C) 2000-2002 MySQL AB This program is free software; you can redistribute it and/or modify @@ -634,3 +637,5 @@ static SYMBOL sql_functions[] = { { "VAR_POP", SYM(VARIANCE_SYM)}, { "VAR_SAMP", SYM(VAR_SAMP_SYM)}, }; + +#endif /* LEX_INCLUDED */ diff --git a/sql/message.h b/sql/message.h index 0e7c282d5a1..97d039352b4 100644 --- a/sql/message.h +++ b/sql/message.h @@ -1,3 +1,6 @@ +#ifndef MESSAGE_INCLUDED +#define MESSAGE_INCLUDED + /* To change or add messages mysqld writes to the Windows error log, run mc.exe message.mc @@ -6,6 +9,8 @@ mc.exe can be installed with Windows SDK, some Visual Studio distributions do not include it. */ + + // // Values are 32 bit values layed out as follows: // @@ -53,3 +58,5 @@ // #define MSG_DEFAULT 0xC0000064L +#endif /* MESSAGE_INCLUDED */ + diff --git a/sql/mysqld_suffix.h b/sql/mysqld_suffix.h index 654d7cf88c1..c7ab212f2a2 100644 --- a/sql/mysqld_suffix.h +++ b/sql/mysqld_suffix.h @@ -1,3 +1,6 @@ +#ifndef MYSQLD_SUFFIX_INCLUDED +#define MYSQLD_SUFFIX_INCLUDED + /* Copyright (C) 2000-2004 MySQL AB This program is free software; you can redistribute it and/or modify @@ -27,3 +30,4 @@ #else #define MYSQL_SERVER_SUFFIX_STR MYSQL_SERVER_SUFFIX_DEF #endif +#endif /* MYSQLD_SUFFIX_INCLUDED */ diff --git a/sql/nt_servc.h b/sql/nt_servc.h index 2f0d07df543..5bee42dedf0 100644 --- a/sql/nt_servc.h +++ b/sql/nt_servc.h @@ -1,3 +1,6 @@ +#ifndef NT_SERVC_INCLUDED +#define NT_SERVC_INCLUDED + /** @file @@ -98,3 +101,5 @@ class NTService }; /* ------------------------- the end -------------------------------------- */ + +#endif /* NT_SERVC_INCLUDED */ diff --git a/sql/partition_element.h b/sql/partition_element.h index 905bc38165b..d67259b9605 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -1,3 +1,6 @@ +#ifndef PARTITION_ELEMENT_INCLUDED +#define PARTITION_ELEMENT_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -97,3 +100,5 @@ public: } ~partition_element() {} }; + +#endif /* PARTITION_ELEMENT_INCLUDED */ diff --git a/sql/partition_info.h b/sql/partition_info.h index 9f438e8260b..b5a6c4a0961 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -1,3 +1,6 @@ +#ifndef PARTITION_INFO_INCLUDED +#define PARTITION_INFO_INCLUDED + /* Copyright 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify @@ -314,3 +317,5 @@ void init_all_partitions_iterator(partition_info *part_info, part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; part_iter->get_next= get_next_partition_id_range; } + +#endif /* PARTITION_INFO_INCLUDED */ diff --git a/sql/procedure.h b/sql/procedure.h index ceb586766b1..c6f50493876 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -1,3 +1,6 @@ +#ifndef PROCEDURE_INCLUDED +#define PROCEDURE_INCLUDED + /* Copyright (C) 2000-2005 MySQL AB This program is free software; you can redistribute it and/or modify @@ -149,3 +152,5 @@ public: Procedure *setup_procedure(THD *thd,ORDER *proc_param,select_result *result, List &field_list,int *error); + +#endif /* PROCEDURE_INCLUDED */ diff --git a/sql/protocol.h b/sql/protocol.h index 251ba6fbc33..a39636a1595 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -1,3 +1,6 @@ +#ifndef PROTOCOL_INCLUDED +#define PROTOCOL_INCLUDED + /* Copyright (C) 2002-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -180,3 +183,4 @@ uchar *net_store_data(uchar *to,const uchar *from, size_t length); uchar *net_store_data(uchar *to,int32 from); uchar *net_store_data(uchar *to,longlong from); +#endif /* PROTOCOL_INCLUDED */ diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h index 6ff78067aca..bce2c727050 100644 --- a/sql/repl_failsafe.h +++ b/sql/repl_failsafe.h @@ -1,3 +1,6 @@ +#ifndef REPL_FAILSAFE_INCLUDED +#define REPL_FAILSAFE_INCLUDED + /* Copyright (C) 2001-2005 MySQL AB & Sasha This program is free software; you can redistribute it and/or modify @@ -49,3 +52,4 @@ int register_slave(THD* thd, uchar* packet, uint packet_length); void unregister_slave(THD* thd, bool only_mine, bool need_mutex); #endif /* HAVE_REPLICATION */ +#endif /* REPL_FAILSAFE_INCLUDED */ diff --git a/sql/scheduler.h b/sql/scheduler.h index 46bbd300cbb..e7916031a27 100644 --- a/sql/scheduler.h +++ b/sql/scheduler.h @@ -1,3 +1,6 @@ +#ifndef SCHEDULER_INCLUDED +#define SCHEDULER_INCLUDED + /* Copyright (C) 2007 MySQL AB This program is free software; you can redistribute it and/or modify @@ -58,3 +61,5 @@ enum pool_command_op class thd_scheduler {}; + +#endif /* SCHEDULER_INCLUDED */ diff --git a/sql/set_var.h b/sql/set_var.h index 10e6e0f9c35..a3ed8e5be15 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -1,3 +1,6 @@ +#ifndef SET_VAR_INCLUDED +#define SET_VAR_INCLUDED + /* Copyright (C) 2002-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -1449,3 +1452,5 @@ void free_key_cache(const char *name, KEY_CACHE *key_cache); bool process_key_caches(process_key_cache_t func); void delete_elements(I_List *list, void (*free_element)(const char*, uchar*)); + +#endif /* SET_VAR_INCLUDED */ diff --git a/sql/sql_acl.h b/sql/sql_acl.h index a8090fba2e7..c0622bd747c 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -1,3 +1,6 @@ +#ifndef SQL_ACL_INCLUDED +#define SQL_ACL_INCLUDED + /* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -273,3 +276,4 @@ bool is_acl_user(const char *host, const char *user); #define check_grant(A,B,C,D,E,F) 0 #define check_grant_db(A,B) 0 #endif +#endif /* SQL_ACL_INCLUDED */ diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 8807b40857e..8f52b90c874 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -1,3 +1,6 @@ +#ifndef SQL_ANALYSE_INCLUDED +#define SQL_ANALYSE_INCLUDED + /* Copyright (C) 2000-2003, 2005 MySQL AB This program is free software; you can redistribute it and/or modify @@ -355,3 +358,5 @@ public: select_result *result, List &field_list); }; + +#endif /* SQL_ANALYSE_INCLUDED */ diff --git a/sql/sql_array.h b/sql/sql_array.h index e1b22921519..dfaa9b02947 100644 --- a/sql/sql_array.h +++ b/sql/sql_array.h @@ -1,3 +1,6 @@ +#ifndef SQL_ARRAY_INCLUDED +#define SQL_ARRAY_INCLUDED + /* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -66,3 +69,4 @@ public: } }; +#endif /* SQL_ARRAY_INCLUDED */ diff --git a/sql/sql_class.h b/sql/sql_class.h index f52d5fae76f..49f9bc3fd5e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -14,6 +14,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef SQL_CLASS_INCLUDED +#define SQL_CLASS_INCLUDED + /* Classes in mysql */ #ifdef USE_PRAGMA_INTERFACE @@ -3003,3 +3006,4 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, void mark_transaction_to_rollback(THD *thd, bool all); #endif /* MYSQL_SERVER */ +#endif /* SQL_CLASS_INCLUDED */ diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h index a5a6bee8a58..8d5a761cbdf 100644 --- a/sql/sql_crypt.h +++ b/sql/sql_crypt.h @@ -1,3 +1,6 @@ +#ifndef SQL_CRYPT_INCLUDED +#define SQL_CRYPT_INCLUDED + /* Copyright (C) 2000-2001, 2005 MySQL AB This program is free software; you can redistribute it and/or modify @@ -35,3 +38,5 @@ class SQL_CRYPT :public Sql_alloc void encode(char *str, uint length); void decode(char *str, uint length); }; + +#endif /* SQL_CRYPT_INCLUDED */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 76fd5354c51..6f9f667a75a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -17,6 +17,9 @@ @defgroup Semantic_Analysis Semantic Analysis */ +#ifndef SQL_LEX_INCLUDED +#define SQL_LEX_INCLUDED + /* YACC and LEX Definitions */ /* These may not be declared yet */ @@ -1979,3 +1982,4 @@ extern bool is_lex_native_function(const LEX_STRING *name); int my_missing_function_error(const LEX_STRING &token, const char *name); #endif /* MYSQL_SERVER */ +#endif /* SQL_LEX_INCLUDED */ diff --git a/sql/sql_map.h b/sql/sql_map.h index a1efba0da6f..5ae260841e0 100644 --- a/sql/sql_map.h +++ b/sql/sql_map.h @@ -1,3 +1,6 @@ +#ifndef SQL_MAP_INCLUDED +#define SQL_MAP_INCLUDED + /* Copyright (C) 2000-2001, 2005 MySQL AB This program is free software; you can redistribute it and/or modify @@ -60,3 +63,5 @@ public: return file->map; } }; + +#endif /* SQL_MAP_INCLUDED */ diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 282e24f1853..0c47340016c 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -1,3 +1,6 @@ +#ifndef SQL_PARTITION_INCLUDED +#define SQL_PARTITION_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -209,3 +212,4 @@ typedef int (*get_partitions_in_range_iter)(partition_info *part_info, #include "partition_info.h" +#endif /* SQL_PARTITION_INCLUDED */ diff --git a/sql/sql_repl.h b/sql/sql_repl.h index d5c9040f8dc..aa71ac96ff8 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -13,6 +13,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef SQL_REPL_INCLUDED +#define SQL_REPL_INCLUDED + #include "rpl_filter.h" #ifdef HAVE_REPLICATION @@ -65,3 +68,4 @@ int init_replication_sys_vars(); #endif /* HAVE_REPLICATION */ +#endif /* SQL_REPL_INCLUDED */ diff --git a/sql/sql_select.h b/sql/sql_select.h index a0366d47149..12cfebfc374 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1,3 +1,6 @@ +#ifndef SQL_SELECT_INCLUDED +#define SQL_SELECT_INCLUDED + /* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -736,3 +739,4 @@ inline bool optimizer_flag(THD *thd, uint flag) return (thd->variables.optimizer_switch & flag); } +#endif /* SQL_SELECT_INCLUDED */ diff --git a/sql/sql_servers.h b/sql/sql_servers.h index 63c691893d1..12855f8473c 100644 --- a/sql/sql_servers.h +++ b/sql/sql_servers.h @@ -1,3 +1,6 @@ +#ifndef SQL_SERVERS_INCLUDED +#define SQL_SERVERS_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -41,3 +44,5 @@ int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options); /* lookup functions */ FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name, FOREIGN_SERVER *server_buffer); + +#endif /* SQL_SERVERS_INCLUDED */ diff --git a/sql/sql_sort.h b/sql/sql_sort.h index 1e9322f7f5b..102b3ef0a11 100644 --- a/sql/sql_sort.h +++ b/sql/sql_sort.h @@ -1,3 +1,6 @@ +#ifndef SQL_SORT_INCLUDED +#define SQL_SORT_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -87,3 +90,5 @@ int merge_buffers(SORTPARAM *param,IO_CACHE *from_file, BUFFPEK *lastbuff,BUFFPEK *Fb, BUFFPEK *Tb,int flag); void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length); + +#endif /* SQL_SORT_INCLUDED */ diff --git a/sql/sql_string.h b/sql/sql_string.h index d62908e5d66..7b10aafbff1 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -1,3 +1,6 @@ +#ifndef SQL_STRING_INCLUDED +#define SQL_STRING_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -389,3 +392,5 @@ static inline bool check_if_only_end_space(CHARSET_INFO *cs, char *str, { return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end; } + +#endif /* SQL_STRING_INCLUDED */ diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index f6754a75284..b411acf2ac5 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -1,3 +1,6 @@ +#ifndef SQL_TRIGGER_INCLUDED +#define SQL_TRIGGER_INCLUDED + /* Copyright (C) 2004-2005 MySQL AB This program is free software; you can redistribute it and/or modify @@ -174,3 +177,4 @@ bool load_table_name_for_trigger(THD *thd, const LEX_STRING *trn_path, LEX_STRING *tbl_name); +#endif /* SQL_TRIGGER_INCLUDED */ diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 4b8b492698e..95cb167869e 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -1,3 +1,6 @@ +#ifndef SQL_UDF_INCLUDED +#define SQL_UDF_INCLUDED + /* Copyright (C) 2000-2001, 2003-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -140,3 +143,4 @@ void free_udf(udf_func *udf); int mysql_create_function(THD *thd,udf_func *udf); int mysql_drop_function(THD *thd,const LEX_STRING *name); #endif +#endif /* SQL_UDF_INCLUDED */ diff --git a/sql/sql_view.h b/sql/sql_view.h index e08c2168e14..3de51c3264e 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -1,3 +1,6 @@ +#ifndef SQL_VIEW_INCLUDED +#define SQL_VIEW_INCLUDED + /* -*- C++ -*- */ /* Copyright (C) 2004 MySQL AB @@ -42,3 +45,4 @@ bool mysql_rename_view(THD *thd, const char *new_db, const char *new_name, #define VIEW_ANY_ACL (SELECT_ACL | UPDATE_ACL | INSERT_ACL | DELETE_ACL) +#endif /* SQL_VIEW_INCLUDED */ diff --git a/sql/structs.h b/sql/structs.h index a58c18f97c5..bcda7b1e787 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -1,3 +1,6 @@ +#ifndef STRUCTS_INCLUDED +#define STRUCTS_INCLUDED + /* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -380,3 +383,5 @@ public: Discrete_interval* get_tail() const { return tail; }; Discrete_interval* get_current() const { return current; }; }; + +#endif /* STRUCTS_INCLUDED */ diff --git a/sql/table.h b/sql/table.h index 40372fa91cf..7c43ab339e5 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1,3 +1,6 @@ +#ifndef TABLE_INCLUDED +#define TABLE_INCLUDED + /* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify @@ -1729,3 +1732,4 @@ static inline void dbug_tmp_restore_column_maps(MY_BITMAP *read_set, size_t max_row_length(TABLE *table, const uchar *data); +#endif /* TABLE_INCLUDED */ diff --git a/sql/tzfile.h b/sql/tzfile.h index 1ff82d62329..1c1800ba1ed 100644 --- a/sql/tzfile.h +++ b/sql/tzfile.h @@ -1,3 +1,6 @@ +#ifndef TZFILE_INCLUDED +#define TZFILE_INCLUDED + /* Copyright (C) 2004 MySQL AB This program is free software; you can redistribute it and/or modify @@ -134,3 +137,5 @@ struct tzhead { */ #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +#endif diff --git a/sql/tztime.h b/sql/tztime.h index 9bf103519c4..9990e91f17b 100644 --- a/sql/tztime.h +++ b/sql/tztime.h @@ -1,3 +1,6 @@ +#ifndef TZTIME_INCLUDED +#define TZTIME_INCLUDED + /* Copyright (C) 2004 MySQL AB This program is free software; you can redistribute it and/or modify @@ -79,3 +82,4 @@ static const int MY_TZ_TABLES_COUNT= 4; #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */ +#endif /* TZTIME_INCLUDED */ diff --git a/sql/unireg.h b/sql/unireg.h index 3ff7f058e3c..6c9080aea79 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -1,3 +1,6 @@ +#ifndef UNIREG_INCLUDED +#define UNIREG_INCLUDED + /* Copyright (C) 2000-2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -16,8 +19,6 @@ /* Extra functions used by unireg library */ -#ifndef _unireg_h - #ifndef NO_ALARM_LOOP #define NO_ALARM_LOOP /* lib5 and popen can't use alarm */ #endif diff --git a/strings/strings-not-used.h b/strings/strings-not-used.h index 3efaa8ab6eb..8311545f22f 100644 --- a/strings/strings-not-used.h +++ b/strings/strings-not-used.h @@ -1,3 +1,6 @@ +#ifndef STRINGS_NOT_USED_INCLUDED +#define STRINGS_NOT_USED_INCLUDED + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -35,3 +38,4 @@ #define _AlphabetSize 256 #endif /* NullS */ +#endif /* STRINGS_NOT_USED_INCLUDED */ diff --git a/vio/vio_priv.h b/vio/vio_priv.h index b9f5dd0c9c4..792fad4cc66 100644 --- a/vio/vio_priv.h +++ b/vio/vio_priv.h @@ -1,3 +1,6 @@ +#ifndef VIO_PRIV_INCLUDED +#define VIO_PRIV_INCLUDED + /* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -38,3 +41,4 @@ void vio_ssl_delete(Vio *vio); int vio_ssl_blocking(Vio *vio, my_bool set_blocking_mode, my_bool *old_mode); #endif /* HAVE_OPENSSL */ +#endif /* VIO_PRIV_INCLUDED */ From 5d2f79def9b67dd5400411070d47f8180ceb072b Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Fri, 25 Sep 2009 11:47:15 +0200 Subject: [PATCH 016/274] Bug #47645: Segmentation fault when out of memory during handlerton initialization There is a missing check for memory allocation failure when allocating memory for the handlerton structure. If the handlerton init function tries to de-reference the pointer, it will cause a segmentation fault and crash the server. This patch fixes the problem by not calling the init function if memory allocation failed, and instead prints an informative error message and reports the error to the caller. sql/handler.cc: Add a check if memory allocation succeeded before calling the init function. If it failed, it is not necessary to free the memory, but the plugin->data is set to NULL to ensure that it can be checked for failure. --- sql/handler.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sql/handler.cc b/sql/handler.cc index e5c64452aaf..f966a9099ee 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -430,6 +430,14 @@ int ha_initialize_handlerton(st_plugin_int *plugin) hton= (handlerton *)my_malloc(sizeof(handlerton), MYF(MY_WME | MY_ZEROFILL)); + + if (hton == NULL) + { + sql_print_error("Unable to allocate memory for plugin '%s' handlerton.", + plugin->name.str); + goto err_no_hton_memory; + } + /* Historical Requirement */ plugin->data= hton; // shortcut for the future if (plugin->plugin->init && plugin->plugin->init(hton)) @@ -540,6 +548,7 @@ err_deinit: err: my_free((uchar*) hton, MYF(0)); +err_no_hton_memory: plugin->data= NULL; DBUG_RETURN(1); } From 623ed58cfda0aef6b6bf545a4200357a58a8a4cc Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Sat, 26 Sep 2009 12:49:49 +0800 Subject: [PATCH 017/274] Backporting WL#4398 WL#1720 Backporting BUG#44058 BUG#42244 BUG#45672 BUG#45673 Backporting BUG#45819 BUG#45973 BUG#39012 --- .bzr-mysql/default.conf | 2 +- include/mysql/plugin.h | 77 +- include/mysql/plugin.h.pp | 12 + libmysqld/CMakeLists.txt | 1 + libmysqld/Makefile.am | 3 +- mysql-test/mysql-test-run.pl | 20 + mysql-test/suite/rpl/t/rpl000017.test | 1 + plugin/semisync/Makefile.am | 35 + plugin/semisync/configure.in | 9 + plugin/semisync/plug.in | 3 + plugin/semisync/semisync.cc | 30 + plugin/semisync/semisync.h | 95 ++ plugin/semisync/semisync_master.cc | 1199 +++++++++++++++++++++ plugin/semisync/semisync_master.h | 366 +++++++ plugin/semisync/semisync_master_plugin.cc | 380 +++++++ plugin/semisync/semisync_slave.cc | 122 +++ plugin/semisync/semisync_slave.h | 99 ++ plugin/semisync/semisync_slave_plugin.cc | 224 ++++ sql/CMakeLists.txt | 1 + sql/Makefile.am | 6 +- sql/handler.cc | 12 + sql/log.cc | 35 +- sql/log.h | 16 +- sql/mysqld.cc | 10 + sql/replication.h | 490 +++++++++ sql/rpl_handler.cc | 493 +++++++++ sql/rpl_handler.h | 213 ++++ sql/slave.cc | 124 ++- sql/sql_class.cc | 36 + sql/sql_class.h | 21 +- sql/sql_parse.cc | 1 + sql/sql_plugin.cc | 17 +- sql/sql_plugin.h | 8 + sql/sql_repl.cc | 164 ++- 34 files changed, 4240 insertions(+), 85 deletions(-) create mode 100644 plugin/semisync/Makefile.am create mode 100644 plugin/semisync/configure.in create mode 100644 plugin/semisync/plug.in create mode 100644 plugin/semisync/semisync.cc create mode 100644 plugin/semisync/semisync.h create mode 100644 plugin/semisync/semisync_master.cc create mode 100644 plugin/semisync/semisync_master.h create mode 100644 plugin/semisync/semisync_master_plugin.cc create mode 100644 plugin/semisync/semisync_slave.cc create mode 100644 plugin/semisync/semisync_slave.h create mode 100644 plugin/semisync/semisync_slave_plugin.cc create mode 100644 sql/replication.h create mode 100644 sql/rpl_handler.cc create mode 100644 sql/rpl_handler.h diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index f044f8e62da..44969de4744 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.1" +tree_name = "mysql-5.1-rep-semisync" diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index 2e59262d061..45d0234cb67 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -16,6 +16,11 @@ #ifndef _my_plugin_h #define _my_plugin_h +/* size_t */ +#include + +typedef struct st_mysql MYSQL; + /* On Windows, exports from DLL need to be declared @@ -75,7 +80,8 @@ typedef struct st_mysql_xid MYSQL_XID; #define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */ #define MYSQL_DAEMON_PLUGIN 3 /* The daemon/raw plugin type */ #define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 /* The I_S plugin type */ -#define MYSQL_MAX_PLUGIN_TYPE_NUM 5 /* The number of plugin types */ +#define MYSQL_REPLICATION_PLUGIN 5 /* The replication plugin type */ +#define MYSQL_MAX_PLUGIN_TYPE_NUM 6 /* The number of plugin types */ /* We use the following strings to define licenses for plugins */ #define PLUGIN_LICENSE_PROPRIETARY 0 @@ -650,6 +656,17 @@ struct st_mysql_information_schema int interface_version; }; +/* + API for Replication plugin. (MYSQL_REPLICATION_PLUGIN) +*/ + #define MYSQL_REPLICATION_INTERFACE_VERSION 0x0100 + + /** + Replication plugin descriptor + */ + struct Mysql_replication { + int interface_version; + }; /* st_mysql_value struct for reading values from mysqld. @@ -801,6 +818,64 @@ void mysql_query_cache_invalidate4(MYSQL_THD thd, const char *key, unsigned int key_length, int using_trx); +/** + Get the value of user variable as an integer. + + This function will return the value of variable @a name as an + integer. If the original value of the variable is not an integer, + the value will be converted into an integer. + + @param name user variable name + @param value pointer to return the value + @param null_value if not NULL, the function will set it to true if + the value of variable is null, set to false if not + + @retval 0 Success + @retval 1 Variable not found +*/ +int get_user_var_int(const char *name, + long long int *value, int *null_value); + +/** + Get the value of user variable as a double precision float number. + + This function will return the value of variable @a name as real + number. If the original value of the variable is not a real number, + the value will be converted into a real number. + + @param name user variable name + @param value pointer to return the value + @param null_value if not NULL, the function will set it to true if + the value of variable is null, set to false if not + + @retval 0 Success + @retval 1 Variable not found +*/ +int get_user_var_real(const char *name, + double *value, int *null_value); + +/** + Get the value of user variable as a string. + + This function will return the value of variable @a name as + string. If the original value of the variable is not a string, + the value will be converted into a string. + + @param name user variable name + @param value pointer to the value buffer + @param len length of the value buffer + @param precision precision of the value if it is a float number + @param null_value if not NULL, the function will set it to true if + the value of variable is null, set to false if not + + @retval 0 Success + @retval 1 Variable not found +*/ +int get_user_var_str(const char *name, + char *value, unsigned long len, + unsigned int precision, int *null_value); + + #ifdef __cplusplus } #endif diff --git a/include/mysql/plugin.h.pp b/include/mysql/plugin.h.pp index 50511f515ab..d864140333b 100644 --- a/include/mysql/plugin.h.pp +++ b/include/mysql/plugin.h.pp @@ -1,3 +1,5 @@ +#include +typedef struct st_mysql MYSQL; struct st_mysql_lex_string { char *str; @@ -105,6 +107,9 @@ struct st_mysql_information_schema { int interface_version; }; +struct Mysql_replication { + int interface_version; +}; struct st_mysql_value { int (*value_type)(struct st_mysql_value *); @@ -137,3 +142,10 @@ void thd_get_xid(const void* thd, MYSQL_XID *xid); void mysql_query_cache_invalidate4(void* thd, const char *key, unsigned int key_length, int using_trx); +int get_user_var_int(const char *name, + long long int *value, int *null_value); +int get_user_var_real(const char *name, + double *value, int *null_value); +int get_user_var_str(const char *name, + char *value, unsigned long len, + unsigned int precision, int *null_value); diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 8500d73863a..f7be98889ef 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -139,6 +139,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc ../sql/partition_info.cc ../sql/sql_connect.cc ../sql/scheduler.cc ../sql/event_parse_data.cc + ../sql/rpl_handler.cc ${GEN_SOURCES} ${LIB_SOURCES}) diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index a9bd8d9e17c..244400e1b8d 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -76,7 +76,8 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \ sql_tablespace.cc \ rpl_injector.cc my_user.c partition_info.cc \ - sql_servers.cc event_parse_data.cc + sql_servers.cc event_parse_data.cc \ + rpl_handler.cc libmysqld_int_a_SOURCES= $(libmysqld_sources) nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 114b6c84aa3..434896df6a5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1815,6 +1815,26 @@ sub environment_setup { $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=;EXAMPLE=".$plugin_filename.";"; } + # -------------------------------------------------------------------------- + # Add the path where mysqld will find semisync plugins + # -------------------------------------------------------------------------- + my $lib_semisync_master_plugin= + mtr_file_exists("$basedir/plugin/semisync/.libs/libsemisync_master.so"); + my $lib_semisync_slave_plugin= + mtr_file_exists("$basedir/plugin/semisync/.libs/libsemisync_slave.so"); + if ($lib_semisync_master_plugin && $lib_semisync_slave_plugin) + { + $ENV{'SEMISYNC_MASTER_PLUGIN'}= basename($lib_semisync_master_plugin); + $ENV{'SEMISYNC_SLAVE_PLUGIN'}= basename($lib_semisync_slave_plugin); + $ENV{'SEMISYNC_PLUGIN_OPT'}= "--plugin-dir=".dirname($lib_semisync_master_plugin); + } + else + { + $ENV{'SEMISYNC_MASTER_PLUGIN'}= ""; + $ENV{'SEMISYNC_SLAVE_PLUGIN'}= ""; + $ENV{'SEMISYNC_PLUGIN_OPT'}=""; + } + # ---------------------------------------------------- # Add the path where mysqld will find mypluglib.so # ---------------------------------------------------- diff --git a/mysql-test/suite/rpl/t/rpl000017.test b/mysql-test/suite/rpl/t/rpl000017.test index 2ba321cd8c3..d6b3e46fa31 100644 --- a/mysql-test/suite/rpl/t/rpl000017.test +++ b/mysql-test/suite/rpl/t/rpl000017.test @@ -6,6 +6,7 @@ grant replication slave on *.* to replicate@localhost identified by 'aaaaaaaaaaa grant replication slave on *.* to replicate@127.0.0.1 identified by 'aaaaaaaaaaaaaaab'; connection slave; start slave; +source include/wait_for_slave_to_start.inc; connection master; --disable_warnings drop table if exists t1; diff --git a/plugin/semisync/Makefile.am b/plugin/semisync/Makefile.am new file mode 100644 index 00000000000..dd9a630670c --- /dev/null +++ b/plugin/semisync/Makefile.am @@ -0,0 +1,35 @@ +# Copyright (C) 2006 MySQL AB +# +# 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 + +## Makefile.am for semi-synchronous replication + +pkgplugindir = $(pkglibdir)/plugin +INCLUDES = -I$(top_srcdir)/include \ + -I$(top_srcdir)/sql \ + -I$(srcdir) + +noinst_HEADERS = semisync.h semisync_master.h semisync_slave.h + +pkgplugin_LTLIBRARIES = libsemisync_master.la libsemisync_slave.la + +libsemisync_master_la_LDFLAGS = -module +libsemisync_master_la_CXXFLAGS= $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN +libsemisync_master_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN +libsemisync_master_la_SOURCES = semisync.cc semisync_master.cc semisync_master_plugin.cc + +libsemisync_slave_la_LDFLAGS = -module +libsemisync_slave_la_CXXFLAGS= $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN +libsemisync_slave_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN +libsemisync_slave_la_SOURCES = semisync.cc semisync_slave.cc semisync_slave_plugin.cc diff --git a/plugin/semisync/configure.in b/plugin/semisync/configure.in new file mode 100644 index 00000000000..894251258db --- /dev/null +++ b/plugin/semisync/configure.in @@ -0,0 +1,9 @@ +# configure.in for semi-synchronous replication + +AC_INIT(mysql-semi-sync-plugin, 0.2) +AM_INIT_AUTOMAKE +AC_DISABLE_STATIC +AC_PROG_LIBTOOL +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT + diff --git a/plugin/semisync/plug.in b/plugin/semisync/plug.in new file mode 100644 index 00000000000..917c8950f02 --- /dev/null +++ b/plugin/semisync/plug.in @@ -0,0 +1,3 @@ +MYSQL_PLUGIN(semisync,[Semi-synchronous Replication Plugin], + [Semi-synchronous replication plugin.]) +MYSQL_PLUGIN_DYNAMIC(semisync, [libsemisync_master.la libsemisync_slave.la]) diff --git a/plugin/semisync/semisync.cc b/plugin/semisync/semisync.cc new file mode 100644 index 00000000000..83c7791c14b --- /dev/null +++ b/plugin/semisync/semisync.cc @@ -0,0 +1,30 @@ +/* Copyright (C) 2007 Google Inc. + Copyright (C) 2008 MySQL AB + + 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 */ + + +#include "semisync.h" + +const unsigned char ReplSemiSyncBase::kPacketMagicNum = 0xef; +const unsigned char ReplSemiSyncBase::kPacketFlagSync = 0x01; + + +const unsigned long Trace::kTraceGeneral = 0x0001; +const unsigned long Trace::kTraceDetail = 0x0010; +const unsigned long Trace::kTraceNetWait = 0x0020; +const unsigned long Trace::kTraceFunction = 0x0040; + +const char ReplSemiSyncBase::kSyncHeader[2] = + {ReplSemiSyncBase::kPacketMagicNum, 0}; diff --git a/plugin/semisync/semisync.h b/plugin/semisync/semisync.h new file mode 100644 index 00000000000..c9d35a093f6 --- /dev/null +++ b/plugin/semisync/semisync.h @@ -0,0 +1,95 @@ +/* Copyright (C) 2007 Google Inc. + Copyright (C) 2008 MySQL AB + + 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 */ + + +#ifndef SEMISYNC_H +#define SEMISYNC_H + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef uint32_t uint32; +typedef unsigned long long my_off_t; +#define FN_REFLEN 512 /* Max length of full path-name */ +void sql_print_error(const char *format, ...); +void sql_print_warning(const char *format, ...); +void sql_print_information(const char *format, ...); +extern unsigned long max_connections; + +#define MYSQL_SERVER +#define HAVE_REPLICATION +#include +#include +#include +#include + +typedef struct st_mysql_show_var SHOW_VAR; +typedef struct st_mysql_sys_var SYS_VAR; + + +/** + This class is used to trace function calls and other process + information +*/ +class Trace { +public: + static const unsigned long kTraceFunction; + static const unsigned long kTraceGeneral; + static const unsigned long kTraceDetail; + static const unsigned long kTraceNetWait; + + unsigned long trace_level_; /* the level for tracing */ + + inline void function_enter(const char *func_name) + { + if (trace_level_ & kTraceFunction) + sql_print_information("---> %s enter", func_name); + } + inline int function_exit(const char *func_name, int exit_code) + { + if (trace_level_ & kTraceFunction) + sql_print_information("<--- %s exit (%d)", func_name, exit_code); + return exit_code; + } + + Trace() + :trace_level_(0L) + {} + Trace(unsigned long trace_level) + :trace_level_(trace_level) + {} +}; + +/** + Base class for semi-sync master and slave classes +*/ +class ReplSemiSyncBase + :public Trace { +public: + static const char kSyncHeader[2]; /* three byte packet header */ + + /* Constants in network packet header. */ + static const unsigned char kPacketMagicNum; + static const unsigned char kPacketFlagSync; +}; + +#endif /* SEMISYNC_H */ diff --git a/plugin/semisync/semisync_master.cc b/plugin/semisync/semisync_master.cc new file mode 100644 index 00000000000..b3454c49829 --- /dev/null +++ b/plugin/semisync/semisync_master.cc @@ -0,0 +1,1199 @@ +/* Copyright (C) 2007 Google Inc. + Copyright (C) 2008 MySQL AB + + 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 */ + + +#include "semisync_master.h" + +#define TIME_THOUSAND 1000 +#define TIME_MILLION 1000000 +#define TIME_BILLION 1000000000 + +/* This indicates whether semi-synchronous replication is enabled. */ +char rpl_semi_sync_master_enabled; +unsigned long rpl_semi_sync_master_timeout; +unsigned long rpl_semi_sync_master_trace_level; +unsigned long rpl_semi_sync_master_status = 0; +unsigned long rpl_semi_sync_master_yes_transactions = 0; +unsigned long rpl_semi_sync_master_no_transactions = 0; +unsigned long rpl_semi_sync_master_off_times = 0; +unsigned long rpl_semi_sync_master_timefunc_fails = 0; +unsigned long rpl_semi_sync_master_num_timeouts = 0; +unsigned long rpl_semi_sync_master_wait_sessions = 0; +unsigned long rpl_semi_sync_master_back_wait_pos = 0; +unsigned long rpl_semi_sync_master_trx_wait_time = 0; +unsigned long long rpl_semi_sync_master_trx_wait_num = 0; +unsigned long rpl_semi_sync_master_net_wait_time = 0; +unsigned long long rpl_semi_sync_master_net_wait_num = 0; +unsigned long rpl_semi_sync_master_clients = 0; +unsigned long long rpl_semi_sync_master_net_wait_total_time = 0; +unsigned long long rpl_semi_sync_master_trx_wait_total_time = 0; + + +static int getWaitTime(const struct timeval& start_tv); + +/******************************************************************************* + * + * class : manage all active transaction nodes + * + ******************************************************************************/ + +ActiveTranx::ActiveTranx(int max_connections, + pthread_mutex_t *lock, + unsigned long trace_level) + : Trace(trace_level), num_transactions_(max_connections), + num_entries_(max_connections << 1), + lock_(lock) +{ + /* Allocate the memory for the array */ + node_array_ = new TranxNode[num_transactions_]; + for (int idx = 0; idx < num_transactions_; ++idx) + { + node_array_[idx].log_pos_ = 0; + node_array_[idx].hash_next_ = NULL; + node_array_[idx].next_ = node_array_ + idx + 1; + + node_array_[idx].log_name_ = new char[FN_REFLEN]; + node_array_[idx].log_name_[0] = '\x0'; + } + node_array_[num_transactions_-1].next_ = NULL; + + /* All nodes in the array go to the pool initially. */ + free_pool_ = node_array_; + + /* No transactions are in the list initially. */ + trx_front_ = NULL; + trx_rear_ = NULL; + + /* Create the hash table to find a transaction's ending event. */ + trx_htb_ = new TranxNode *[num_entries_]; + for (int idx = 0; idx < num_entries_; ++idx) + trx_htb_[idx] = NULL; + + sql_print_information("Semi-sync replication initialized for %d " + "transactions.", num_transactions_); +} + +ActiveTranx::~ActiveTranx() +{ + for (int idx = 0; idx < num_transactions_; ++idx) + { + delete [] node_array_[idx].log_name_; + node_array_[idx].log_name_ = NULL; + } + + delete [] node_array_; + delete [] trx_htb_; + + node_array_ = NULL; + trx_htb_ = NULL; + num_transactions_ = 0; + num_entries_ = 0; +} + +unsigned int ActiveTranx::calc_hash(const unsigned char *key, + unsigned int length) +{ + unsigned int nr = 1, nr2 = 4; + + /* The hash implementation comes from calc_hashnr() in mysys/hash.c. */ + while (length--) + { + nr ^= (((nr & 63)+nr2)*((unsigned int) (unsigned char) *key++))+ (nr << 8); + nr2 += 3; + } + return((unsigned int) nr); +} + +unsigned int ActiveTranx::get_hash_value(const char *log_file_name, + my_off_t log_file_pos) +{ + unsigned int hash1 = calc_hash((const unsigned char *)log_file_name, + strlen(log_file_name)); + unsigned int hash2 = calc_hash((const unsigned char *)(&log_file_pos), + sizeof(log_file_pos)); + + return (hash1 + hash2) % num_entries_; +} + +ActiveTranx::TranxNode* ActiveTranx::alloc_tranx_node() +{ + TranxNode *ptr = free_pool_; + + if (free_pool_) + { + free_pool_ = free_pool_->next_; + ptr->next_ = NULL; + ptr->hash_next_ = NULL; + } + else + { + /* + free_pool should never be NULL here, because we have + max_connections number of pre-allocated nodes. + */ + sql_print_error("You have encountered a semi-sync bug (free_pool == NULL), " + "please report to http://bugs.mysql.com"); + assert(free_pool_); + } + + return ptr; +} + +int ActiveTranx::compare(const char *log_file_name1, my_off_t log_file_pos1, + const char *log_file_name2, my_off_t log_file_pos2) +{ + int cmp = strcmp(log_file_name1, log_file_name2); + + if (cmp != 0) + return cmp; + + if (log_file_pos1 > log_file_pos2) + return 1; + else if (log_file_pos1 < log_file_pos2) + return -1; + return 0; +} + +int ActiveTranx::insert_tranx_node(const char *log_file_name, + my_off_t log_file_pos) +{ + const char *kWho = "ActiveTranx:insert_tranx_node"; + TranxNode *ins_node; + int result = 0; + unsigned int hash_val; + + function_enter(kWho); + + ins_node = alloc_tranx_node(); + if (!ins_node) + { + sql_print_error("%s: transaction node allocation failed for: (%s, %lu)", + kWho, log_file_name, (unsigned long)log_file_pos); + result = -1; + goto l_end; + } + + /* insert the binlog position in the active transaction list. */ + strcpy(ins_node->log_name_, log_file_name); + ins_node->log_pos_ = log_file_pos; + + if (!trx_front_) + { + /* The list is empty. */ + trx_front_ = trx_rear_ = ins_node; + } + else + { + int cmp = compare(ins_node, trx_rear_); + if (cmp > 0) + { + /* Compare with the tail first. If the transaction happens later in + * binlog, then make it the new tail. + */ + trx_rear_->next_ = ins_node; + trx_rear_ = ins_node; + } + else + { + /* Otherwise, it is an error because the transaction should hold the + * mysql_bin_log.LOCK_log when appending events. + */ + sql_print_error("%s: binlog write out-of-order, tail (%s, %lu), " + "new node (%s, %lu)", kWho, + trx_rear_->log_name_, (unsigned long)trx_rear_->log_pos_, + ins_node->log_name_, (unsigned long)ins_node->log_pos_); + result = -1; + goto l_end; + } + } + + hash_val = get_hash_value(ins_node->log_name_, ins_node->log_pos_); + ins_node->hash_next_ = trx_htb_[hash_val]; + trx_htb_[hash_val] = ins_node; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: insert (%s, %lu) in entry(%u)", kWho, + ins_node->log_name_, (unsigned long)ins_node->log_pos_, + hash_val); + + l_end: + return function_exit(kWho, result); +} + +bool ActiveTranx::is_tranx_end_pos(const char *log_file_name, + my_off_t log_file_pos) +{ + const char *kWho = "ActiveTranx::is_tranx_end_pos"; + function_enter(kWho); + + unsigned int hash_val = get_hash_value(log_file_name, log_file_pos); + TranxNode *entry = trx_htb_[hash_val]; + + while (entry != NULL) + { + if (compare(entry, log_file_name, log_file_pos) == 0) + break; + + entry = entry->hash_next_; + } + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: probe (%s, %lu) in entry(%u)", kWho, + log_file_name, (unsigned long)log_file_pos, hash_val); + + function_exit(kWho, (entry != NULL)); + return (entry != NULL); +} + +int ActiveTranx::clear_active_tranx_nodes(const char *log_file_name, + my_off_t log_file_pos) +{ + const char *kWho = "ActiveTranx::::clear_active_tranx_nodes"; + TranxNode *new_front; + + function_enter(kWho); + + if (log_file_name != NULL) + { + new_front = trx_front_; + + while (new_front) + { + if (compare(new_front, log_file_name, log_file_pos) > 0) + break; + new_front = new_front->next_; + } + } + else + { + /* If log_file_name is NULL, clear everything. */ + new_front = NULL; + } + + if (new_front == NULL) + { + /* No active transaction nodes after the call. */ + + /* Clear the hash table. */ + memset(trx_htb_, 0, num_entries_ * sizeof(TranxNode *)); + + /* Clear the active transaction list. */ + if (trx_front_ != NULL) + { + trx_rear_->next_ = free_pool_; + free_pool_ = trx_front_; + trx_front_ = NULL; + trx_rear_ = NULL; + } + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: free all nodes back to free list", kWho); + } + else if (new_front != trx_front_) + { + TranxNode *curr_node, *next_node; + + /* Delete all transaction nodes before the confirmation point. */ + int n_frees = 0; + curr_node = trx_front_; + while (curr_node != new_front) + { + next_node = curr_node->next_; + + /* Put the node in the memory pool. */ + curr_node->next_ = free_pool_; + free_pool_ = curr_node; + n_frees++; + + /* Remove the node from the hash table. */ + unsigned int hash_val = get_hash_value(curr_node->log_name_, curr_node->log_pos_); + TranxNode **hash_ptr = &(trx_htb_[hash_val]); + while ((*hash_ptr) != NULL) + { + if ((*hash_ptr) == curr_node) + { + (*hash_ptr) = curr_node->hash_next_; + break; + } + hash_ptr = &((*hash_ptr)->hash_next_); + } + + curr_node = next_node; + } + + trx_front_ = new_front; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: free %d nodes back until pos (%s, %lu)", + kWho, n_frees, + trx_front_->log_name_, (unsigned long)trx_front_->log_pos_); + } + + return function_exit(kWho, 0); +} + + +/******************************************************************************* + * + * class: the basic code layer for sync-replication master. + * class: the basic code layer for sync-replication slave. + * + * The most important functions during semi-syn replication listed: + * + * Master: + * . reportReplyBinlog(): called by the binlog dump thread when it receives + * the slave's status information. + * . updateSyncHeader(): based on transaction waiting information, decide + * whether to request the slave to reply. + * . writeTraxInBinlog(): called by the transaction thread when it finishes + * writing all transaction events in binlog. + * . commitTrx(): transaction thread wait for the slave reply. + * + * Slave: + * . slaveReadSyncHeader(): read the semi-sync header from the master, get the + * sync status and get the payload for events. + * . slaveReply(): reply to the master about the replication progress. + * + ******************************************************************************/ + +ReplSemiSyncMaster::ReplSemiSyncMaster() + : active_tranxs_(NULL), + init_done_(false), + reply_file_name_inited_(false), + reply_file_pos_(0L), + wait_file_name_inited_(false), + wait_file_pos_(0), + master_enabled_(false), + wait_timeout_(0L), + state_(0), + enabled_transactions_(0), + disabled_transactions_(0), + switched_off_times_(0), + timefunc_fails_(0), + wait_sessions_(0), + wait_backtraverse_(0), + total_trx_wait_num_(0), + total_trx_wait_time_(0), + total_net_wait_num_(0), + total_net_wait_time_(0), + max_transactions_(0L) +{ + strcpy(reply_file_name_, ""); + strcpy(wait_file_name_, ""); +} + +int ReplSemiSyncMaster::initObject() +{ + int result; + const char *kWho = "ReplSemiSyncMaster::initObject"; + + if (init_done_) + { + fprintf(stderr, "%s called twice\n", kWho); + return 1; + } + init_done_ = true; + + /* References to the parameter works after set_options(). */ + setWaitTimeout(rpl_semi_sync_master_timeout); + setTraceLevel(rpl_semi_sync_master_trace_level); + max_transactions_ = (int)max_connections; + + /* Mutex initialization can only be done after MY_INIT(). */ + pthread_mutex_init(&LOCK_binlog_, MY_MUTEX_INIT_FAST); + pthread_cond_init(&COND_binlog_send_, NULL); + + if (rpl_semi_sync_master_enabled) + result = enableMaster(); + else + result = disableMaster(); + + return result; +} + +int ReplSemiSyncMaster::enableMaster() +{ + int result = 0; + + /* Must have the lock when we do enable of disable. */ + lock(); + + if (!getMasterEnabled()) + { + active_tranxs_ = new ActiveTranx(max_connections, + &LOCK_binlog_, + trace_level_); + if (active_tranxs_ != NULL) + { + commit_file_name_inited_ = false; + reply_file_name_inited_ = false; + wait_file_name_inited_ = false; + + set_master_enabled(true); + state_ = true; + sql_print_information("Semi-sync replication enabled on the master."); + } + else + { + sql_print_error("Cannot allocate memory to enable semi-sync on the master."); + result = -1; + } + } + + unlock(); + + return result; +} + +int ReplSemiSyncMaster::disableMaster() +{ + /* Must have the lock when we do enable of disable. */ + lock(); + + if (getMasterEnabled()) + { + /* Switch off the semi-sync first so that waiting transaction will be + * waken up. + */ + switch_off(); + + assert(active_tranxs_ != NULL); + delete active_tranxs_; + active_tranxs_ = NULL; + + reply_file_name_inited_ = false; + wait_file_name_inited_ = false; + commit_file_name_inited_ = false; + + set_master_enabled(false); + sql_print_information("Semi-sync replication disabled on the master."); + } + + unlock(); + + return 0; +} + +ReplSemiSyncMaster::~ReplSemiSyncMaster() +{ + if (init_done_) + { + pthread_mutex_destroy(&LOCK_binlog_); + pthread_cond_destroy(&COND_binlog_send_); + } + + delete active_tranxs_; +} + +void ReplSemiSyncMaster::lock() +{ + pthread_mutex_lock(&LOCK_binlog_); +} + +void ReplSemiSyncMaster::unlock() +{ + pthread_mutex_unlock(&LOCK_binlog_); +} + +void ReplSemiSyncMaster::cond_broadcast() +{ + pthread_cond_broadcast(&COND_binlog_send_); +} + +int ReplSemiSyncMaster::cond_timewait(struct timespec *wait_time) +{ + const char *kWho = "ReplSemiSyncMaster::cond_timewait()"; + int wait_res; + + function_enter(kWho); + wait_res = pthread_cond_timedwait(&COND_binlog_send_, + &LOCK_binlog_, wait_time); + return function_exit(kWho, wait_res); +} + +void ReplSemiSyncMaster::add_slave() +{ + lock(); + rpl_semi_sync_master_clients++; + unlock(); +} + +void ReplSemiSyncMaster::remove_slave() +{ + lock(); + rpl_semi_sync_master_clients--; + unlock(); +} + +bool ReplSemiSyncMaster::is_semi_sync_slave() +{ + int null_value; + long long val= 0; + get_user_var_int("rpl_semi_sync_slave", &val, &null_value); + return val; +} + +int ReplSemiSyncMaster::reportReplyBinlog(const char *log_file_pos) +{ + char log_name[FN_REFLEN]; + char *endptr; + my_off_t log_pos= strtoull(log_file_pos, &endptr, 10); + if (!log_pos || !endptr || *endptr != ':' ) + return 1; + endptr++; // skip the ':' seperator + strncpy(log_name, endptr, FN_REFLEN); + uint32 server_id= 0; + return reportReplyBinlog(server_id, log_name, log_pos); +} + +int ReplSemiSyncMaster::reportReplyBinlog(uint32 server_id, + const char *log_file_name, + my_off_t log_file_pos) +{ + const char *kWho = "ReplSemiSyncMaster::reportReplyBinlog"; + int cmp; + bool can_release_threads = false; + bool need_copy_send_pos = true; + + if (!(getMasterEnabled())) + return 0; + + function_enter(kWho); + + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) + goto l_end; + + if (!is_on()) + /* We check to see whether we can switch semi-sync ON. */ + try_switch_on(server_id, log_file_name, log_file_pos); + + /* The position should increase monotonically, if there is only one + * thread sending the binlog to the slave. + * In reality, to improve the transaction availability, we allow multiple + * sync replication slaves. So, if any one of them get the transaction, + * the transaction session in the primary can move forward. + */ + if (reply_file_name_inited_) + { + cmp = ActiveTranx::compare(log_file_name, log_file_pos, + reply_file_name_, reply_file_pos_); + + /* If the requested position is behind the sending binlog position, + * would not adjust sending binlog position. + * We based on the assumption that there are multiple semi-sync slave, + * and at least one of them shou/ld be up to date. + * If all semi-sync slaves are behind, at least initially, the primary + * can find the situation after the waiting timeout. After that, some + * slaves should catch up quickly. + */ + if (cmp < 0) + { + /* If the position is behind, do not copy it. */ + need_copy_send_pos = false; + } + } + + if (need_copy_send_pos) + { + strcpy(reply_file_name_, log_file_name); + reply_file_pos_ = log_file_pos; + reply_file_name_inited_ = true; + + /* Remove all active transaction nodes before this point. */ + assert(active_tranxs_ != NULL); + active_tranxs_->clear_active_tranx_nodes(log_file_name, log_file_pos); + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: Got reply at (%s, %lu)", kWho, + log_file_name, (unsigned long)log_file_pos); + } + + if (wait_sessions_ > 0) + { + /* Let us check if some of the waiting threads doing a trx + * commit can now proceed. + */ + cmp = ActiveTranx::compare(reply_file_name_, reply_file_pos_, + wait_file_name_, wait_file_pos_); + if (cmp >= 0) + { + /* Yes, at least one waiting thread can now proceed: + * let us release all waiting threads with a broadcast + */ + can_release_threads = true; + wait_file_name_inited_ = false; + } + } + + l_end: + unlock(); + + if (can_release_threads) + { + if (trace_level_ & kTraceDetail) + sql_print_information("%s: signal all waiting threads.", kWho); + + cond_broadcast(); + } + + return function_exit(kWho, 0); +} + +int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name, + my_off_t trx_wait_binlog_pos) +{ + const char *kWho = "ReplSemiSyncMaster::commitTrx"; + + function_enter(kWho); + + if (getMasterEnabled() && trx_wait_binlog_name) + { + struct timeval start_tv; + struct timespec abstime; + int wait_result, start_time_err; + const char *old_msg= 0; + + start_time_err = gettimeofday(&start_tv, 0); + + /* Acquire the mutex. */ + lock(); + + /* This must be called after acquired the lock */ + old_msg= thd_enter_cond(NULL, &COND_binlog_send_, &LOCK_binlog_, + "Waiting for semi-sync ACK from slave"); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled() || !is_on() || !rpl_semi_sync_master_clients) + goto l_end; + + if (trace_level_ & kTraceDetail) + { + sql_print_information("%s: wait pos (%s, %lu), repl(%d)\n", kWho, + trx_wait_binlog_name, (unsigned long)trx_wait_binlog_pos, + (int)is_on()); + } + + while (is_on()) + { + int cmp = ActiveTranx::compare(reply_file_name_, reply_file_pos_, + trx_wait_binlog_name, trx_wait_binlog_pos); + if (cmp >= 0) + { + /* We have already sent the relevant binlog to the slave: no need to + * wait here. + */ + if (trace_level_ & kTraceDetail) + sql_print_information("%s: Binlog reply is ahead (%s, %lu),", + kWho, reply_file_name_, (unsigned long)reply_file_pos_); + break; + } + + /* Let us update the info about the minimum binlog position of waiting + * threads. + */ + if (wait_file_name_inited_) + { + cmp = ActiveTranx::compare(trx_wait_binlog_name, trx_wait_binlog_pos, + wait_file_name_, wait_file_pos_); + if (cmp <= 0) + { + /* This thd has a lower position, let's update the minimum info. */ + strcpy(wait_file_name_, trx_wait_binlog_name); + wait_file_pos_ = trx_wait_binlog_pos; + + wait_backtraverse_++; + if (trace_level_ & kTraceDetail) + sql_print_information("%s: move back wait position (%s, %lu),", + kWho, wait_file_name_, (unsigned long)wait_file_pos_); + } + } + else + { + strcpy(wait_file_name_, trx_wait_binlog_name); + wait_file_pos_ = trx_wait_binlog_pos; + wait_file_name_inited_ = true; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: init wait position (%s, %lu),", + kWho, wait_file_name_, (unsigned long)wait_file_pos_); + } + + if (start_time_err == 0) + { + int diff_usecs = start_tv.tv_usec + wait_timeout_ * TIME_THOUSAND; + + /* Calcuate the waiting period. */ + abstime.tv_sec = start_tv.tv_sec; + if (diff_usecs < TIME_MILLION) + { + abstime.tv_nsec = diff_usecs * TIME_THOUSAND; + } + else + { + while (diff_usecs >= TIME_MILLION) + { + abstime.tv_sec++; + diff_usecs -= TIME_MILLION; + } + abstime.tv_nsec = diff_usecs * TIME_THOUSAND; + } + + /* In semi-synchronous replication, we wait until the binlog-dump + * thread has received the reply on the relevant binlog segment from the + * replication slave. + * + * Let us suspend this thread to wait on the condition; + * when replication has progressed far enough, we will release + * these waiting threads. + */ + wait_sessions_++; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: wait %lu ms for binlog sent (%s, %lu)", + kWho, wait_timeout_, + wait_file_name_, (unsigned long)wait_file_pos_); + + wait_result = cond_timewait(&abstime); + wait_sessions_--; + + if (wait_result != 0) + { + /* This is a real wait timeout. */ + sql_print_warning("Timeout waiting for reply of binlog (file: %s, pos: %lu), " + "semi-sync up to file %s, position %lu.", + trx_wait_binlog_name, (unsigned long)trx_wait_binlog_pos, + reply_file_name_, (unsigned long)reply_file_pos_); + total_wait_timeouts_++; + + /* switch semi-sync off */ + switch_off(); + } + else + { + int wait_time; + + wait_time = getWaitTime(start_tv); + if (wait_time < 0) + { + if (trace_level_ & kTraceGeneral) + { + /* This is a time/gettimeofday function call error. */ + sql_print_error("Replication semi-sync gettimeofday fail1 at " + "wait position (%s, %lu)", + trx_wait_binlog_name, (unsigned long)trx_wait_binlog_pos); + } + timefunc_fails_++; + } + else + { + total_trx_wait_num_++; + total_trx_wait_time_ += wait_time; + } + } + } + else + { + if (trace_level_ & kTraceGeneral) + { + /* This is a gettimeofday function call error. */ + sql_print_error("Replication semi-sync gettimeofday fail2 at " + "wait position (%s, %lu)", + trx_wait_binlog_name, (unsigned long)trx_wait_binlog_pos); + } + timefunc_fails_++; + + /* switch semi-sync off */ + switch_off(); + } + } + + l_end: + /* Update the status counter. */ + if (is_on() && rpl_semi_sync_master_clients) + enabled_transactions_++; + else + disabled_transactions_++; + + /* The lock held will be released by thd_exit_cond, so no need to + call unlock() here */ + thd_exit_cond(NULL, old_msg); + } + + return function_exit(kWho, 0); +} + +/* Indicate that semi-sync replication is OFF now. + * + * What should we do when it is disabled? The problem is that we want + * the semi-sync replication enabled again when the slave catches up + * later. But, it is not that easy to detect that the slave has caught + * up. This is caused by the fact that MySQL's replication protocol is + * asynchronous, meaning that if the master does not use the semi-sync + * protocol, the slave would not send anything to the master. + * Still, if the master is sending (N+1)-th event, we assume that it is + * an indicator that the slave has received N-th event and earlier ones. + * + * If semi-sync is disabled, all transactions still update the wait + * position with the last position in binlog. But no transactions will + * wait for confirmations and the active transaction list would not be + * maintained. In binlog dump thread, updateSyncHeader() checks whether + * the current sending event catches up with last wait position. If it + * does match, semi-sync will be switched on again. + */ +int ReplSemiSyncMaster::switch_off() +{ + const char *kWho = "ReplSemiSyncMaster::switch_off"; + int result; + + function_enter(kWho); + state_ = false; + + /* Clear the active transaction list. */ + assert(active_tranxs_ != NULL); + result = active_tranxs_->clear_active_tranx_nodes(NULL, 0); + + switched_off_times_++; + wait_file_name_inited_ = false; + reply_file_name_inited_ = false; + sql_print_information("Semi-sync replication switched OFF."); + cond_broadcast(); /* wake up all waiting threads */ + + return function_exit(kWho, result); +} + +int ReplSemiSyncMaster::try_switch_on(int server_id, + const char *log_file_name, + my_off_t log_file_pos) +{ + const char *kWho = "ReplSemiSyncMaster::try_switch_on"; + bool semi_sync_on = false; + + function_enter(kWho); + + /* If the current sending event's position is larger than or equal to the + * 'largest' commit transaction binlog position, the slave is already + * catching up now and we can switch semi-sync on here. + * If commit_file_name_inited_ indicates there are no recent transactions, + * we can enable semi-sync immediately. + */ + if (commit_file_name_inited_) + { + int cmp = ActiveTranx::compare(log_file_name, log_file_pos, + commit_file_name_, commit_file_pos_); + semi_sync_on = (cmp >= 0); + } + else + { + semi_sync_on = true; + } + + if (semi_sync_on) + { + /* Switch semi-sync replication on. */ + state_ = true; + + sql_print_information("Semi-sync replication switched ON with slave (server_id: %d) " + "at (%s, %lu)", + server_id, log_file_name, + (unsigned long)log_file_pos); + } + + return function_exit(kWho, 0); +} + +int ReplSemiSyncMaster::reserveSyncHeader(unsigned char *header, + unsigned long size) +{ + const char *kWho = "ReplSemiSyncMaster::reserveSyncHeader"; + function_enter(kWho); + + int hlen=0; + if (!is_semi_sync_slave()) + { + hlen= 0; + } + else + { + /* No enough space for the extra header, disable semi-sync master */ + if (sizeof(kSyncHeader) > size) + { + sql_print_warning("No enough space in the packet " + "for semi-sync extra header, " + "semi-sync replication disabled"); + disableMaster(); + return 0; + } + + /* Set the magic number and the sync status. By default, no sync + * is required. + */ + memcpy(header, kSyncHeader, sizeof(kSyncHeader)); + hlen= sizeof(kSyncHeader); + } + return function_exit(kWho, hlen); +} + +int ReplSemiSyncMaster::updateSyncHeader(unsigned char *packet, + const char *log_file_name, + my_off_t log_file_pos, + uint32 server_id) +{ + const char *kWho = "ReplSemiSyncMaster::updateSyncHeader"; + int cmp = 0; + bool sync = false; + + /* If the semi-sync master is not enabled, or the slave is not a semi-sync + * target, do not request replies from the slave. + */ + if (!getMasterEnabled() || !is_semi_sync_slave()) + { + sync = false; + return 0; + } + + function_enter(kWho); + + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) + { + sync = false; + goto l_end; + } + + if (is_on()) + { + /* semi-sync is ON */ + sync = false; /* No sync unless a transaction is involved. */ + + if (reply_file_name_inited_) + { + cmp = ActiveTranx::compare(log_file_name, log_file_pos, + reply_file_name_, reply_file_pos_); + if (cmp <= 0) + { + /* If we have already got the reply for the event, then we do + * not need to sync the transaction again. + */ + goto l_end; + } + } + + if (wait_file_name_inited_) + { + cmp = ActiveTranx::compare(log_file_name, log_file_pos, + wait_file_name_, wait_file_pos_); + } + else + { + cmp = 1; + } + + /* If we are already waiting for some transaction replies which + * are later in binlog, do not wait for this one event. + */ + if (cmp >= 0) + { + /* + * We only wait if the event is a transaction's ending event. + */ + assert(active_tranxs_ != NULL); + sync = active_tranxs_->is_tranx_end_pos(log_file_name, + log_file_pos); + } + } + else + { + if (commit_file_name_inited_) + { + int cmp = ActiveTranx::compare(log_file_name, log_file_pos, + commit_file_name_, commit_file_pos_); + sync = (cmp >= 0); + } + else + { + sync = true; + } + } + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: server(%d), (%s, %lu) sync(%d), repl(%d)", + kWho, server_id, log_file_name, + (unsigned long)log_file_pos, sync, (int)is_on()); + + l_end: + unlock(); + + /* We do not need to clear sync flag because we set it to 0 when we + * reserve the packet header. + */ + if (sync) + (packet)[2] = kPacketFlagSync; + + return function_exit(kWho, 0); +} + +int ReplSemiSyncMaster::writeTranxInBinlog(const char* log_file_name, + my_off_t log_file_pos) +{ + const char *kWho = "ReplSemiSyncMaster::writeTranxInBinlog"; + int result = 0; + + function_enter(kWho); + + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) + goto l_end; + + /* Update the 'largest' transaction commit position seen so far even + * though semi-sync is switched off. + * It is much better that we update commit_file_* here, instead of + * inside commitTrx(). This is mostly because updateSyncHeader() + * will watch for commit_file_* to decide whether to switch semi-sync + * on. The detailed reason is explained in function updateSyncHeader(). + */ + if (commit_file_name_inited_) + { + int cmp = ActiveTranx::compare(log_file_name, log_file_pos, + commit_file_name_, commit_file_pos_); + if (cmp > 0) + { + /* This is a larger position, let's update the maximum info. */ + strcpy(commit_file_name_, log_file_name); + commit_file_pos_ = log_file_pos; + } + } + else + { + strcpy(commit_file_name_, log_file_name); + commit_file_pos_ = log_file_pos; + commit_file_name_inited_ = true; + } + + if (is_on() && rpl_semi_sync_master_clients) + { + assert(active_tranxs_ != NULL); + if(active_tranxs_->insert_tranx_node(log_file_name, log_file_pos)) + { + /* + if insert tranx_node failed, print a warning message + and turn off semi-sync + */ + sql_print_warning("Semi-sync failed to insert tranx_node for binlog file: %s, position: %ul", + log_file_name, log_file_pos); + switch_off(); + } + } + + l_end: + unlock(); + + return function_exit(kWho, result); +} + +int ReplSemiSyncMaster::resetMaster() +{ + const char *kWho = "ReplSemiSyncMaster::resetMaster"; + int result = 0; + + function_enter(kWho); + + + lock(); + + state_ = getMasterEnabled()? 1 : 0; + + wait_file_name_inited_ = false; + reply_file_name_inited_ = false; + commit_file_name_inited_ = false; + + enabled_transactions_ = 0; + disabled_transactions_ = 0; + switched_off_times_ = 0; + timefunc_fails_ = 0; + wait_sessions_ = 0; + wait_backtraverse_ = 0; + total_trx_wait_num_ = 0; + total_trx_wait_time_ = 0; + total_net_wait_num_ = 0; + total_net_wait_time_ = 0; + + unlock(); + + return function_exit(kWho, result); +} + +void ReplSemiSyncMaster::setExportStats() +{ + lock(); + + rpl_semi_sync_master_status = state_ && rpl_semi_sync_master_clients; + rpl_semi_sync_master_yes_transactions = enabled_transactions_; + rpl_semi_sync_master_no_transactions = disabled_transactions_; + rpl_semi_sync_master_off_times = switched_off_times_; + rpl_semi_sync_master_timefunc_fails = timefunc_fails_; + rpl_semi_sync_master_num_timeouts = total_wait_timeouts_; + rpl_semi_sync_master_wait_sessions = wait_sessions_; + rpl_semi_sync_master_back_wait_pos = wait_backtraverse_; + rpl_semi_sync_master_trx_wait_num = total_trx_wait_num_; + rpl_semi_sync_master_trx_wait_time = + ((total_trx_wait_num_) ? + (unsigned long)((double)total_trx_wait_time_ / + ((double)total_trx_wait_num_)) : 0); + rpl_semi_sync_master_net_wait_num = total_net_wait_num_; + rpl_semi_sync_master_net_wait_time = + ((total_net_wait_num_) ? + (unsigned long)((double)total_net_wait_time_ / + ((double)total_net_wait_num_)) : 0); + + rpl_semi_sync_master_net_wait_total_time = total_net_wait_time_; + rpl_semi_sync_master_trx_wait_total_time = total_trx_wait_time_; + + unlock(); +} + +/* Get the waiting time given the wait's staring time. + * + * Return: + * >= 0: the waiting time in microsecons(us) + * < 0: error in gettimeofday or time back traverse + */ +static int getWaitTime(const struct timeval& start_tv) +{ + unsigned long long start_usecs, end_usecs; + struct timeval end_tv; + int end_time_err; + + /* Starting time in microseconds(us). */ + start_usecs = start_tv.tv_sec * TIME_MILLION + start_tv.tv_usec; + + /* Get the wait time interval. */ + end_time_err = gettimeofday(&end_tv, 0); + + /* Ending time in microseconds(us). */ + end_usecs = end_tv.tv_sec * TIME_MILLION + end_tv.tv_usec; + + if (end_time_err != 0 || end_usecs < start_usecs) + return -1; + + return (int)(end_usecs - start_usecs); +} diff --git a/plugin/semisync/semisync_master.h b/plugin/semisync/semisync_master.h new file mode 100644 index 00000000000..a1697b2ae67 --- /dev/null +++ b/plugin/semisync/semisync_master.h @@ -0,0 +1,366 @@ +/* Copyright (C) 2007 Google Inc. + Copyright (C) 2008 MySQL AB + + 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 */ + + +#ifndef SEMISYNC_MASTER_H +#define SEMISYNC_MASTER_H + +#include "semisync.h" + +/** + This class manages memory for active transaction list. + + We record each active transaction with a TranxNode. Because each + session can only have only one open transaction, the total active + transaction nodes can not exceed the maximum sessions. Currently + in MySQL, sessions are the same as connections. +*/ +class ActiveTranx + :public Trace { +private: + struct TranxNode { + char *log_name_; + my_off_t log_pos_; + struct TranxNode *next_; /* the next node in the sorted list */ + struct TranxNode *hash_next_; /* the next node during hash collision */ + }; + + /* The following data structure maintains an active transaction list. */ + TranxNode *node_array_; + TranxNode *free_pool_; + + /* These two record the active transaction list in sort order. */ + TranxNode *trx_front_, *trx_rear_; + + TranxNode **trx_htb_; /* A hash table on active transactions. */ + + int num_transactions_; /* maximum transactions */ + int num_entries_; /* maximum hash table entries */ + pthread_mutex_t *lock_; /* mutex lock */ + + inline void assert_lock_owner(); + + inline TranxNode* alloc_tranx_node(); + + inline unsigned int calc_hash(const unsigned char *key,unsigned int length); + unsigned int get_hash_value(const char *log_file_name, my_off_t log_file_pos); + + int compare(const char *log_file_name1, my_off_t log_file_pos1, + const TranxNode *node2) { + return compare(log_file_name1, log_file_pos1, + node2->log_name_, node2->log_pos_); + } + int compare(const TranxNode *node1, + const char *log_file_name2, my_off_t log_file_pos2) { + return compare(node1->log_name_, node1->log_pos_, + log_file_name2, log_file_pos2); + } + int compare(const TranxNode *node1, const TranxNode *node2) { + return compare(node1->log_name_, node1->log_pos_, + node2->log_name_, node2->log_pos_); + } + +public: + ActiveTranx(int max_connections, pthread_mutex_t *lock, + unsigned long trace_level); + ~ActiveTranx(); + + /* Insert an active transaction node with the specified position. + * + * Return: + * 0: success; -1 or otherwise: error + */ + int insert_tranx_node(const char *log_file_name, my_off_t log_file_pos); + + /* Clear the active transaction nodes until(inclusive) the specified + * position. + * If log_file_name is NULL, everything will be cleared: the sorted + * list and the hash table will be reset to empty. + * + * Return: + * 0: success; -1 or otherwise: error + */ + int clear_active_tranx_nodes(const char *log_file_name, + my_off_t log_file_pos); + + /* Given a position, check to see whether the position is an active + * transaction's ending position by probing the hash table. + */ + bool is_tranx_end_pos(const char *log_file_name, my_off_t log_file_pos); + + /* Given two binlog positions, compare which one is bigger based on + * (file_name, file_position). + */ + static int compare(const char *log_file_name1, my_off_t log_file_pos1, + const char *log_file_name2, my_off_t log_file_pos2); + +}; + +/** + The extension class for the master of semi-synchronous replication +*/ +class ReplSemiSyncMaster + :public ReplSemiSyncBase { + private: + ActiveTranx *active_tranxs_; /* active transaction list: the list will + be cleared when semi-sync switches off. */ + + /* True when initObject has been called */ + bool init_done_; + + /* This cond variable is signaled when enough binlog has been sent to slave, + * so that a waiting trx can return the 'ok' to the client for a commit. + */ + pthread_cond_t COND_binlog_send_; + + /* Mutex that protects the following state variables and the active + * transaction list. + * Under no cirumstances we can acquire mysql_bin_log.LOCK_log if we are + * already holding LOCK_binlog_ because it can cause deadlocks. + */ + pthread_mutex_t LOCK_binlog_; + + /* This is set to true when reply_file_name_ contains meaningful data. */ + bool reply_file_name_inited_; + + /* The binlog name up to which we have received replies from any slaves. */ + char reply_file_name_[FN_REFLEN]; + + /* The position in that file up to which we have the reply from any slaves. */ + my_off_t reply_file_pos_; + + /* This is set to true when we know the 'smallest' wait position. */ + bool wait_file_name_inited_; + + /* NULL, or the 'smallest' filename that a transaction is waiting for + * slave replies. + */ + char wait_file_name_[FN_REFLEN]; + + /* The smallest position in that file that a trx is waiting for: the trx + * can proceed and send an 'ok' to the client when the master has got the + * reply from the slave indicating that it already got the binlog events. + */ + my_off_t wait_file_pos_; + + /* This is set to true when we know the 'largest' transaction commit + * position in the binlog file. + * We always maintain the position no matter whether semi-sync is switched + * on switched off. When a transaction wait timeout occurs, semi-sync will + * switch off. Binlog-dump thread can use the three fields to detect when + * slaves catch up on replication so that semi-sync can switch on again. + */ + bool commit_file_name_inited_; + + /* The 'largest' binlog filename that a commit transaction is seeing. */ + char commit_file_name_[FN_REFLEN]; + + /* The 'largest' position in that file that a commit transaction is seeing. */ + my_off_t commit_file_pos_; + + /* All global variables which can be set by parameters. */ + volatile bool master_enabled_; /* semi-sync is enabled on the master */ + unsigned long wait_timeout_; /* timeout period(ms) during tranx wait */ + + /* All status variables. */ + bool state_; /* whether semi-sync is switched */ + unsigned long enabled_transactions_; /* semi-sync'ed tansactions */ + unsigned long disabled_transactions_; /* non-semi-sync'ed tansactions */ + unsigned long switched_off_times_; /* how many times are switched off? */ + unsigned long timefunc_fails_; /* how many time function fails? */ + unsigned long total_wait_timeouts_; /* total number of wait timeouts */ + unsigned long wait_sessions_; /* how many sessions wait for replies? */ + unsigned long wait_backtraverse_; /* wait position back traverses */ + unsigned long long total_trx_wait_num_; /* total trx waits: non-timeout ones */ + unsigned long long total_trx_wait_time_; /* total trx wait time: in us */ + unsigned long long total_net_wait_num_; /* total network waits */ + unsigned long long total_net_wait_time_; /* total network wait time */ + + /* The number of maximum active transactions. This should be the same as + * maximum connections because MySQL does not do connection sharing now. + */ + int max_transactions_; + + void lock(); + void unlock(); + void cond_broadcast(); + int cond_timewait(struct timespec *wait_time); + + /* Is semi-sync replication on? */ + bool is_on() { + return (state_); + } + + void set_master_enabled(bool enabled) { + master_enabled_ = enabled; + } + + /* Switch semi-sync off because of timeout in transaction waiting. */ + int switch_off(); + + /* Switch semi-sync on when slaves catch up. */ + int try_switch_on(int server_id, + const char *log_file_name, my_off_t log_file_pos); + + public: + ReplSemiSyncMaster(); + ~ReplSemiSyncMaster(); + + bool getMasterEnabled() { + return master_enabled_; + } + void setTraceLevel(unsigned long trace_level) { + trace_level_ = trace_level; + if (active_tranxs_) + active_tranxs_->trace_level_ = trace_level; + } + + /* Set the transaction wait timeout period, in milliseconds. */ + void setWaitTimeout(unsigned long wait_timeout) { + wait_timeout_ = wait_timeout; + } + + /* Initialize this class after MySQL parameters are initialized. this + * function should be called once at bootstrap time. + */ + int initObject(); + + /* Enable the object to enable semi-sync replication inside the master. */ + int enableMaster(); + + /* Enable the object to enable semi-sync replication inside the master. */ + int disableMaster(); + + /* Add a semi-sync replication slave */ + void add_slave(); + + /* Remove a semi-sync replication slave */ + void remove_slave(); + + /* Is the slave servered by the thread requested semi-sync */ + bool is_semi_sync_slave(); + + int reportReplyBinlog(const char *log_file_pos); + + /* In semi-sync replication, reports up to which binlog position we have + * received replies from the slave indicating that it already get the events. + * + * Input: + * server_id - (IN) master server id number + * log_file_name - (IN) binlog file name + * end_offset - (IN) the offset in the binlog file up to which we have + * the replies from the slave + * + * Return: + * 0: success; -1 or otherwise: error + */ + int reportReplyBinlog(uint32 server_id, + const char* log_file_name, + my_off_t end_offset); + + /* Commit a transaction in the final step. This function is called from + * InnoDB before returning from the low commit. If semi-sync is switch on, + * the function will wait to see whether binlog-dump thread get the reply for + * the events of the transaction. Remember that this is not a direct wait, + * instead, it waits to see whether the binlog-dump thread has reached the + * point. If the wait times out, semi-sync status will be switched off and + * all other transaction would not wait either. + * + * Input: (the transaction events' ending binlog position) + * trx_wait_binlog_name - (IN) ending position's file name + * trx_wait_binlog_pos - (IN) ending position's file offset + * + * Return: + * 0: success; -1 or otherwise: error + */ + int commitTrx(const char* trx_wait_binlog_name, + my_off_t trx_wait_binlog_pos); + + /* Reserve space in the replication event packet header: + * . slave semi-sync off: 1 byte - (0) + * . slave semi-sync on: 3 byte - (0, 0xef, 0/1} + * + * Input: + * header - (IN) the header buffer + * size - (IN) size of the header buffer + * + * Return: + * size of the bytes reserved for header + */ + int reserveSyncHeader(unsigned char *header, unsigned long size); + + /* Update the sync bit in the packet header to indicate to the slave whether + * the master will wait for the reply of the event. If semi-sync is switched + * off and we detect that the slave is catching up, we switch semi-sync on. + * + * Input: + * packet - (IN) the packet containing the replication event + * log_file_name - (IN) the event ending position's file name + * log_file_pos - (IN) the event ending position's file offset + * server_id - (IN) master server id number + * + * Return: + * 0: success; -1 or otherwise: error + */ + int updateSyncHeader(unsigned char *packet, + const char *log_file_name, + my_off_t log_file_pos, + uint32 server_id); + + /* Called when a transaction finished writing binlog events. + * . update the 'largest' transactions' binlog event position + * . insert the ending position in the active transaction list if + * semi-sync is on + * + * Input: (the transaction events' ending binlog position) + * log_file_name - (IN) transaction ending position's file name + * log_file_pos - (IN) transaction ending position's file offset + * + * Return: + * 0: success; -1 or otherwise: error + */ + int writeTranxInBinlog(const char* log_file_name, my_off_t log_file_pos); + + /* Export internal statistics for semi-sync replication. */ + void setExportStats(); + + /* 'reset master' command is issued from the user and semi-sync need to + * go off for that. + */ + int resetMaster(); +}; + +/* System and status variables for the master component */ +extern char rpl_semi_sync_master_enabled; +extern unsigned long rpl_semi_sync_master_timeout; +extern unsigned long rpl_semi_sync_master_trace_level; +extern unsigned long rpl_semi_sync_master_status; +extern unsigned long rpl_semi_sync_master_yes_transactions; +extern unsigned long rpl_semi_sync_master_no_transactions; +extern unsigned long rpl_semi_sync_master_off_times; +extern unsigned long rpl_semi_sync_master_timefunc_fails; +extern unsigned long rpl_semi_sync_master_num_timeouts; +extern unsigned long rpl_semi_sync_master_wait_sessions; +extern unsigned long rpl_semi_sync_master_back_wait_pos; +extern unsigned long rpl_semi_sync_master_trx_wait_time; +extern unsigned long rpl_semi_sync_master_net_wait_time; +extern unsigned long long rpl_semi_sync_master_net_wait_num; +extern unsigned long long rpl_semi_sync_master_trx_wait_num; +extern unsigned long long rpl_semi_sync_master_net_wait_total_time; +extern unsigned long long rpl_semi_sync_master_trx_wait_total_time; +extern unsigned long rpl_semi_sync_master_clients; + +#endif /* SEMISYNC_MASTER_H */ diff --git a/plugin/semisync/semisync_master_plugin.cc b/plugin/semisync/semisync_master_plugin.cc new file mode 100644 index 00000000000..dc19d09e622 --- /dev/null +++ b/plugin/semisync/semisync_master_plugin.cc @@ -0,0 +1,380 @@ +/* Copyright (C) 2007 Google Inc. + Copyright (C) 2008 MySQL AB + + 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 */ + + +#include "semisync_master.h" + +ReplSemiSyncMaster repl_semisync; + +int repl_semi_report_binlog_update(Binlog_storage_param *param, + const char *log_file, + my_off_t log_pos, uint32 flags) +{ + int error= 0; + + if (repl_semisync.getMasterEnabled()) + { + /* + Let us store the binlog file name and the position, so that + we know how long to wait for the binlog to the replicated to + the slave in synchronous replication. + */ + error= repl_semisync.writeTranxInBinlog(log_file, + log_pos); + } + + return error; +} + +int repl_semi_request_commit(Trans_param *param) +{ + return 0; +} + +int repl_semi_report_commit(Trans_param *param) +{ + + bool is_real_trans= param->flags & TRANS_IS_REAL_TRANS; + + if (is_real_trans && param->log_pos) + { + const char *binlog_name= param->log_file; + return repl_semisync.commitTrx(binlog_name, param->log_pos); + } + return 0; +} + +int repl_semi_report_rollback(Trans_param *param) +{ + return repl_semi_report_commit(param); +} + +int repl_semi_binlog_dump_start(Binlog_transmit_param *param, + const char *log_file, + my_off_t log_pos) +{ + bool semi_sync_slave= repl_semisync.is_semi_sync_slave(); + + if (semi_sync_slave) + /* One more semi-sync slave */ + repl_semisync.add_slave(); + sql_print_information("Start %s binlog_dump to slave (server_id: %d), pos(%s, %lu)", + semi_sync_slave ? "semi-sync" : "asynchronous", + param->server_id, log_file, (unsigned long)log_pos); + + return 0; +} + +int repl_semi_binlog_dump_end(Binlog_transmit_param *param) +{ + bool semi_sync_slave= repl_semisync.is_semi_sync_slave(); + + sql_print_information("Stop %s binlog_dump to slave (server_id: %d)", + semi_sync_slave ? "semi-sync" : "asynchronous", + param->server_id); + if (semi_sync_slave) + { + /* One less semi-sync slave */ + repl_semisync.remove_slave(); + } + return 0; +} + +int repl_semi_reserve_header(Binlog_transmit_param *param, + unsigned char *header, + unsigned long size, unsigned long *len) +{ + *len += repl_semisync.reserveSyncHeader(header, size); + return 0; +} + +int repl_semi_before_send_event(Binlog_transmit_param *param, + unsigned char *packet, unsigned long len, + const char *log_file, my_off_t log_pos) +{ + return repl_semisync.updateSyncHeader(packet, + log_file, + log_pos, + param->server_id); +} + +int repl_semi_after_send_event(Binlog_transmit_param *param, + const char *event_buf, unsigned long len) +{ + return 0; +} + +int repl_semi_reset_master(Binlog_transmit_param *param) +{ + if (repl_semisync.resetMaster()) + return 1; + return 0; +} + +/* + semisync system variables + */ +static void fix_rpl_semi_sync_master_timeout(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val); + +static void fix_rpl_semi_sync_master_trace_level(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val); + +static void fix_rpl_semi_sync_master_enabled(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val); + +static void fix_rpl_semi_sync_master_reply_log_file_pos(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val); + +static MYSQL_SYSVAR_BOOL(enabled, rpl_semi_sync_master_enabled, + PLUGIN_VAR_OPCMDARG, + "Enable semi-synchronous replication master (disabled by default). ", + NULL, // check + &fix_rpl_semi_sync_master_enabled, // update + 0); + +static MYSQL_SYSVAR_ULONG(timeout, rpl_semi_sync_master_timeout, + PLUGIN_VAR_OPCMDARG, + "The timeout value (in ms) for semi-synchronous replication in the master", + NULL, // check + fix_rpl_semi_sync_master_timeout, // update + 10000, 0, ~0L, 1); + +static MYSQL_SYSVAR_ULONG(trace_level, rpl_semi_sync_master_trace_level, + PLUGIN_VAR_OPCMDARG, + "The tracing level for semi-sync replication.", + NULL, // check + &fix_rpl_semi_sync_master_trace_level, // update + 32, 0, ~0L, 1); + +/* + Use a SESSION instead of GLOBAL variable for slave to send reply to + avoid requiring SUPER privilege. +*/ +static MYSQL_THDVAR_STR(reply_log_file_pos, + PLUGIN_VAR_NOCMDOPT, + "The log filename and position slave has queued to relay log.", + NULL, // check + &fix_rpl_semi_sync_master_reply_log_file_pos, + ""); + +static SYS_VAR* semi_sync_master_system_vars[]= { + MYSQL_SYSVAR(enabled), + MYSQL_SYSVAR(timeout), + MYSQL_SYSVAR(trace_level), + MYSQL_SYSVAR(reply_log_file_pos), + NULL, +}; + + +static void fix_rpl_semi_sync_master_timeout(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val) +{ + *(unsigned long *)ptr= *(unsigned long *)val; + repl_semisync.setWaitTimeout(rpl_semi_sync_master_timeout); + return; +} + +static void fix_rpl_semi_sync_master_trace_level(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val) +{ + *(unsigned long *)ptr= *(unsigned long *)val; + repl_semisync.setTraceLevel(rpl_semi_sync_master_trace_level); + return; +} + +static void fix_rpl_semi_sync_master_enabled(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val) +{ + *(char *)ptr= *(char *)val; + if (rpl_semi_sync_master_enabled) + { + if (repl_semisync.enableMaster() != 0) + rpl_semi_sync_master_enabled = false; + } + else + { + if (repl_semisync.disableMaster() != 0) + rpl_semi_sync_master_enabled = true; + } + + return; +} + +static void fix_rpl_semi_sync_master_reply_log_file_pos(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val) +{ + const char *log_file_pos= *(char **)val; + + if (repl_semisync.reportReplyBinlog(log_file_pos)) + sql_print_error("report slave binlog reply failed."); + + return; +} + +Trans_observer trans_observer = { + sizeof(Trans_observer), // len + + repl_semi_report_commit, // after_commit + repl_semi_report_rollback, // after_rollback +}; + +Binlog_storage_observer storage_observer = { + sizeof(Binlog_storage_observer), // len + + repl_semi_report_binlog_update, // report_update +}; + +Binlog_transmit_observer transmit_observer = { + sizeof(Binlog_transmit_observer), // len + + repl_semi_binlog_dump_start, // start + repl_semi_binlog_dump_end, // stop + repl_semi_reserve_header, // reserve_header + repl_semi_before_send_event, // before_send_event + repl_semi_after_send_event, // after_send_event + repl_semi_reset_master, // reset +}; + + +#define SHOW_FNAME(name) \ + rpl_semi_sync_master_show_##name + +#define DEF_SHOW_FUNC(name, show_type) \ + static int SHOW_FNAME(name)(MYSQL_THD thd, SHOW_VAR *var, char *buff) \ + { \ + repl_semisync.setExportStats(); \ + var->type= show_type; \ + var->value= (char *)&rpl_semi_sync_master_##name; \ + return 0; \ + } + +DEF_SHOW_FUNC(clients, SHOW_LONG) +DEF_SHOW_FUNC(net_wait_time, SHOW_LONG) +DEF_SHOW_FUNC(net_wait_total_time, SHOW_LONGLONG) +DEF_SHOW_FUNC(net_wait_num, SHOW_LONGLONG) +DEF_SHOW_FUNC(off_times, SHOW_LONG) +DEF_SHOW_FUNC(no_transactions, SHOW_LONG) +DEF_SHOW_FUNC(status, SHOW_BOOL) +DEF_SHOW_FUNC(timefunc_fails, SHOW_LONG) +DEF_SHOW_FUNC(trx_wait_time, SHOW_LONG) +DEF_SHOW_FUNC(trx_wait_total_time, SHOW_LONGLONG) +DEF_SHOW_FUNC(trx_wait_num, SHOW_LONGLONG) +DEF_SHOW_FUNC(back_wait_pos, SHOW_LONG) +DEF_SHOW_FUNC(wait_sessions, SHOW_LONG) +DEF_SHOW_FUNC(yes_transactions, SHOW_LONG) + + +/* plugin status variables */ +static SHOW_VAR semi_sync_master_status_vars[]= { + {"Rpl_semi_sync_master_clients", (char*) &SHOW_FNAME(clients), SHOW_FUNC}, + {"Rpl_semi_sync_master_net_avg_wait_time", + (char*) &SHOW_FNAME(net_wait_time), SHOW_FUNC}, + {"Rpl_semi_sync_master_net_wait_time", + (char*) &SHOW_FNAME(net_wait_total_time), SHOW_FUNC}, + {"Rpl_semi_sync_master_net_waits", (char*) &SHOW_FNAME(net_wait_num), SHOW_FUNC}, + {"Rpl_semi_sync_master_no_times", (char*) &SHOW_FNAME(off_times), SHOW_FUNC}, + {"Rpl_semi_sync_master_no_tx", (char*) &SHOW_FNAME(no_transactions), SHOW_FUNC}, + {"Rpl_semi_sync_master_status", (char*) &SHOW_FNAME(status), SHOW_FUNC}, + {"Rpl_semi_sync_master_timefunc_failures", + (char*) &SHOW_FNAME(timefunc_fails), SHOW_FUNC}, + {"Rpl_semi_sync_master_tx_avg_wait_time", + (char*) &SHOW_FNAME(trx_wait_time), SHOW_FUNC}, + {"Rpl_semi_sync_master_tx_wait_time", + (char*) &SHOW_FNAME(trx_wait_total_time), SHOW_FUNC}, + {"Rpl_semi_sync_master_tx_waits", (char*) &SHOW_FNAME(trx_wait_num), SHOW_FUNC}, + {"Rpl_semi_sync_master_wait_pos_backtraverse", + (char*) &SHOW_FNAME(back_wait_pos), SHOW_FUNC}, + {"Rpl_semi_sync_master_wait_sessions", + (char*) &SHOW_FNAME(wait_sessions), SHOW_FUNC}, + {"Rpl_semi_sync_master_yes_tx", (char*) &SHOW_FNAME(yes_transactions), SHOW_FUNC}, + {NULL, NULL, SHOW_LONG}, +}; + + +static int semi_sync_master_plugin_init(void *p) +{ + if (repl_semisync.initObject()) + return 1; + if (register_trans_observer(&trans_observer, p)) + return 1; + if (register_binlog_storage_observer(&storage_observer, p)) + return 1; + if (register_binlog_transmit_observer(&transmit_observer, p)) + return 1; + return 0; +} + +static int semi_sync_master_plugin_deinit(void *p) +{ + if (unregister_trans_observer(&trans_observer, p)) + { + sql_print_error("unregister_trans_observer failed"); + return 1; + } + if (unregister_binlog_storage_observer(&storage_observer, p)) + { + sql_print_error("unregister_binlog_storage_observer failed"); + return 1; + } + if (unregister_binlog_transmit_observer(&transmit_observer, p)) + { + sql_print_error("unregister_binlog_transmit_observer failed"); + return 1; + } + sql_print_information("unregister_replicator OK"); + return 0; +} + +struct Mysql_replication semi_sync_master_plugin= { + MYSQL_REPLICATION_INTERFACE_VERSION +}; + +/* + Plugin library descriptor +*/ +mysql_declare_plugin(semi_sync_master) +{ + MYSQL_REPLICATION_PLUGIN, + &semi_sync_master_plugin, + "rpl_semi_sync_master", + "He Zhenxing", + "Semi-synchronous replication master", + PLUGIN_LICENSE_GPL, + semi_sync_master_plugin_init, /* Plugin Init */ + semi_sync_master_plugin_deinit, /* Plugin Deinit */ + 0x0100 /* 1.0 */, + semi_sync_master_status_vars, /* status variables */ + semi_sync_master_system_vars, /* system variables */ + NULL /* config options */ +} +mysql_declare_plugin_end; diff --git a/plugin/semisync/semisync_slave.cc b/plugin/semisync/semisync_slave.cc new file mode 100644 index 00000000000..f6bbb17ce9d --- /dev/null +++ b/plugin/semisync/semisync_slave.cc @@ -0,0 +1,122 @@ +/* Copyright (C) 2008 MySQL AB + + 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 */ + + +#include "semisync_slave.h" + +char rpl_semi_sync_slave_enabled; +unsigned long rpl_semi_sync_slave_status= 0; +unsigned long rpl_semi_sync_slave_trace_level; + +int ReplSemiSyncSlave::initObject() +{ + int result= 0; + const char *kWho = "ReplSemiSyncSlave::initObject"; + + if (init_done_) + { + fprintf(stderr, "%s called twice\n", kWho); + return 1; + } + init_done_ = true; + + /* References to the parameter works after set_options(). */ + setSlaveEnabled(rpl_semi_sync_slave_enabled); + setTraceLevel(rpl_semi_sync_slave_trace_level); + + return result; +} + +int ReplSemiSyncSlave::slaveReplyConnect() +{ + if (!mysql_reply && !(mysql_reply= rpl_connect_master(NULL))) + { + sql_print_error("Semisync slave connect to master for reply failed"); + return 1; + } + return 0; +} + +int ReplSemiSyncSlave::slaveReadSyncHeader(const char *header, + unsigned long total_len, + bool *need_reply, + const char **payload, + unsigned long *payload_len) +{ + const char *kWho = "ReplSemiSyncSlave::slaveReadSyncHeader"; + int read_res = 0; + function_enter(kWho); + + if ((unsigned char)(header[0]) == kPacketMagicNum) + { + *need_reply = (header[1] & kPacketFlagSync); + *payload_len = total_len - 2; + *payload = header + 2; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: reply - %d", kWho, *need_reply); + } + else + { + sql_print_error("Missing magic number for semi-sync packet, packet " + "len: %lu", total_len); + read_res = -1; + } + + return function_exit(kWho, read_res); +} + +int ReplSemiSyncSlave::slaveStart(Binlog_relay_IO_param *param) +{ + bool semi_sync= getSlaveEnabled(); + + sql_print_information("Slave I/O thread: Start %s replication to\ + master '%s@%s:%d' in log '%s' at position %lu", + semi_sync ? "semi-sync" : "asynchronous", + param->user, param->host, param->port, + param->master_log_name[0] ? param->master_log_name : "FIRST", + (unsigned long)param->master_log_pos); + + if (semi_sync && !rpl_semi_sync_slave_status) + rpl_semi_sync_slave_status= 1; + return 0; +} + +int ReplSemiSyncSlave::slaveStop(Binlog_relay_IO_param *param) +{ + if (rpl_semi_sync_slave_status) + rpl_semi_sync_slave_status= 0; + if (mysql_reply) + mysql_close(mysql_reply); + mysql_reply= 0; + return 0; +} + +int ReplSemiSyncSlave::slaveReply(const char *log_name, my_off_t log_pos) +{ + char query[FN_REFLEN + 100]; + sprintf(query, "SET SESSION rpl_semi_sync_master_reply_log_file_pos='%llu:%s'", + (unsigned long long)log_pos, log_name); + if (mysql_real_query(mysql_reply, query, strlen(query))) + { + sql_print_error("Set 'rpl_semi_sync_master_reply_log_file_pos' on master failed"); + mysql_free_result(mysql_store_result(mysql_reply)); + mysql_close(mysql_reply); + mysql_reply= 0; + return 1; + } + mysql_free_result(mysql_store_result(mysql_reply)); + return 0; +} diff --git a/plugin/semisync/semisync_slave.h b/plugin/semisync/semisync_slave.h new file mode 100644 index 00000000000..73bc8aeeade --- /dev/null +++ b/plugin/semisync/semisync_slave.h @@ -0,0 +1,99 @@ +/* Copyright (C) 2006 MySQL AB + + 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 */ + + +#ifndef SEMISYNC_SLAVE_H +#define SEMISYNC_SLAVE_H + +#include "semisync.h" + +/** + The extension class for the slave of semi-synchronous replication +*/ +class ReplSemiSyncSlave + :public ReplSemiSyncBase { +public: + ReplSemiSyncSlave() + :slave_enabled_(false) + {} + ~ReplSemiSyncSlave() {} + + void setTraceLevel(unsigned long trace_level) { + trace_level_ = trace_level; + } + + /* Initialize this class after MySQL parameters are initialized. this + * function should be called once at bootstrap time. + */ + int initObject(); + + bool getSlaveEnabled() { + return slave_enabled_; + } + void setSlaveEnabled(bool enabled) { + slave_enabled_ = enabled; + } + + /* A slave reads the semi-sync packet header and separate the metadata + * from the payload data. + * + * Input: + * header - (IN) packet header pointer + * total_len - (IN) total packet length: metadata + payload + * need_reply - (IN) whether the master is waiting for the reply + * payload - (IN) payload: the replication event + * payload_len - (IN) payload length + * + * Return: + * 0: success; -1 or otherwise: error + */ + int slaveReadSyncHeader(const char *header, unsigned long total_len, bool *need_reply, + const char **payload, unsigned long *payload_len); + + /* A slave replies to the master indicating its replication process. It + * indicates that the slave has received all events before the specified + * binlog position. + * + * Input: + * log_name - (IN) the reply point's binlog file name + * log_pos - (IN) the reply point's binlog file offset + * + * Return: + * 0: success; -1 or otherwise: error + */ + int slaveReply(const char *log_name, my_off_t log_pos); + + /* + Connect to master for sending reply + */ + int slaveReplyConnect(); + + int slaveStart(Binlog_relay_IO_param *param); + int slaveStop(Binlog_relay_IO_param *param); + +private: + /* True when initObject has been called */ + bool init_done_; + bool slave_enabled_; /* semi-sycn is enabled on the slave */ + MYSQL *mysql_reply; /* connection to send reply */ +}; + + +/* System and status variables for the slave component */ +extern char rpl_semi_sync_slave_enabled; +extern unsigned long rpl_semi_sync_slave_trace_level; +extern unsigned long rpl_semi_sync_slave_status; + +#endif /* SEMISYNC_SLAVE_H */ diff --git a/plugin/semisync/semisync_slave_plugin.cc b/plugin/semisync/semisync_slave_plugin.cc new file mode 100644 index 00000000000..ffc663c9bdb --- /dev/null +++ b/plugin/semisync/semisync_slave_plugin.cc @@ -0,0 +1,224 @@ +/* Copyright (C) 2007 Google Inc. + Copyright (C) 2008 MySQL AB + + 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 */ + + +#include "semisync_slave.h" + +ReplSemiSyncSlave repl_semisync; + +/* + indicate whether or not the slave should send a reply to the master. + + This is set to true in repl_semi_slave_read_event if the current + event read is the last event of a transaction. And the value is + checked in repl_semi_slave_queue_event. +*/ +bool semi_sync_need_reply= false; + +int repl_semi_reset_slave(Binlog_relay_IO_param *param) +{ + // TODO: reset semi-sync slave status here + return 0; +} + +int repl_semi_slave_request_dump(Binlog_relay_IO_param *param, + uint32 flags) +{ + MYSQL *mysql= param->mysql; + MYSQL_RES *res= 0; + MYSQL_ROW row; + const char *query; + + if (!repl_semisync.getSlaveEnabled()) + return 0; + + /* + Create the connection that is used to send slave ACK replies to + master + */ + if (repl_semisync.slaveReplyConnect()) + return 1; + + /* Check if master server has semi-sync plugin installed */ + query= "SHOW VARIABLES LIKE 'rpl_semi_sync_master_enabled'"; + if (mysql_real_query(mysql, query, strlen(query)) || + !(res= mysql_store_result(mysql))) + { + mysql_free_result(mysql_store_result(mysql)); + sql_print_error("Execution failed on master: %s", query); + return 1; + } + + row= mysql_fetch_row(res); + if (!row || strcmp(row[1], "ON")) + { + /* Master does not support or not configured semi-sync */ + sql_print_warning("Master server does not support or not configured semi-sync replication, fallback to asynchronous"); + rpl_semi_sync_slave_status= 0; + return 0; + } + + /* + Tell master dump thread that we want to do semi-sync + replication + */ + query= "SET @rpl_semi_sync_slave= 1"; + if (mysql_real_query(mysql, query, strlen(query))) + { + sql_print_error("Set 'rpl_semi_sync_slave=1' on master failed"); + mysql_free_result(mysql_store_result(mysql)); + return 1; + } + mysql_free_result(mysql_store_result(mysql)); + rpl_semi_sync_slave_status= 1; + return 0; +} + +int repl_semi_slave_read_event(Binlog_relay_IO_param *param, + const char *packet, unsigned long len, + const char **event_buf, unsigned long *event_len) +{ + if (rpl_semi_sync_slave_status) + return repl_semisync.slaveReadSyncHeader(packet, len, + &semi_sync_need_reply, + event_buf, event_len); + *event_buf= packet; + *event_len= len; + return 0; +} + +int repl_semi_slave_queue_event(Binlog_relay_IO_param *param, + const char *event_buf, + unsigned long event_len, + uint32 flags) +{ + if (rpl_semi_sync_slave_status && semi_sync_need_reply) + return repl_semisync.slaveReply(param->master_log_name, + param->master_log_pos); + return 0; +} + +int repl_semi_slave_io_start(Binlog_relay_IO_param *param) +{ + return repl_semisync.slaveStart(param); +} + +int repl_semi_slave_io_end(Binlog_relay_IO_param *param) +{ + return repl_semisync.slaveStop(param); +} + + +static void fix_rpl_semi_sync_slave_enabled(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val) +{ + *(char *)ptr= *(char *)val; + repl_semisync.setSlaveEnabled(rpl_semi_sync_slave_enabled != 0); + return; +} + +static void fix_rpl_semi_sync_trace_level(MYSQL_THD thd, + SYS_VAR *var, + void *ptr, + const void *val) +{ + *(unsigned long *)ptr= *(unsigned long *)val; + repl_semisync.setTraceLevel(rpl_semi_sync_slave_trace_level); + return; +} + +/* plugin system variables */ +static MYSQL_SYSVAR_BOOL(enabled, rpl_semi_sync_slave_enabled, + PLUGIN_VAR_OPCMDARG, + "Enable semi-synchronous replication slave (disabled by default). ", + NULL, // check + &fix_rpl_semi_sync_slave_enabled, // update + 0); + +static MYSQL_SYSVAR_ULONG(trace_level, rpl_semi_sync_slave_trace_level, + PLUGIN_VAR_OPCMDARG, + "The tracing level for semi-sync replication.", + NULL, // check + &fix_rpl_semi_sync_trace_level, // update + 32, 0, ~0L, 1); + +static SYS_VAR* semi_sync_slave_system_vars[]= { + MYSQL_SYSVAR(enabled), + MYSQL_SYSVAR(trace_level), + NULL, +}; + + +/* plugin status variables */ +static SHOW_VAR semi_sync_slave_status_vars[]= { + {"Rpl_semi_sync_slave_status", + (char*) &rpl_semi_sync_slave_status, SHOW_BOOL}, + {NULL, NULL, SHOW_BOOL}, +}; + +Binlog_relay_IO_observer relay_io_observer = { + sizeof(Binlog_relay_IO_observer), // len + + repl_semi_slave_io_start, // start + repl_semi_slave_io_end, // stop + repl_semi_slave_request_dump, // request_transmit + repl_semi_slave_read_event, // after_read_event + repl_semi_slave_queue_event, // after_queue_event + repl_semi_reset_slave, // reset +}; + +static int semi_sync_slave_plugin_init(void *p) +{ + if (repl_semisync.initObject()) + return 1; + if (register_binlog_relay_io_observer(&relay_io_observer, p)) + return 1; + return 0; +} + +static int semi_sync_slave_plugin_deinit(void *p) +{ + if (unregister_binlog_relay_io_observer(&relay_io_observer, p)) + return 1; + return 0; +} + + +struct Mysql_replication semi_sync_slave_plugin= { + MYSQL_REPLICATION_INTERFACE_VERSION +}; + +/* + Plugin library descriptor +*/ +mysql_declare_plugin(semi_sync_slave) +{ + MYSQL_REPLICATION_PLUGIN, + &semi_sync_slave_plugin, + "rpl_semi_sync_slave", + "He Zhenxing", + "Semi-synchronous replication slave", + PLUGIN_LICENSE_GPL, + semi_sync_slave_plugin_init, /* Plugin Init */ + semi_sync_slave_plugin_deinit, /* Plugin Deinit */ + 0x0100 /* 1.0 */, + semi_sync_slave_status_vars, /* status variables */ + semi_sync_slave_system_vars, /* system variables */ + NULL /* config options */ +} +mysql_declare_plugin_end; diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 6f162f4d84d..18508468f60 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -75,6 +75,7 @@ SET (SQL_SOURCE rpl_rli.cc rpl_mi.cc sql_servers.cc sql_connect.cc scheduler.cc sql_profile.cc event_parse_data.cc + rpl_handler.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h ${PROJECT_SOURCE_DIR}/include/mysqld_error.h diff --git a/sql/Makefile.am b/sql/Makefile.am index 2a12de2eaf6..afce7db59f2 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -76,7 +76,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ sql_plugin.h authors.h event_parse_data.h \ event_data_objects.h event_scheduler.h \ sql_partition.h partition_info.h partition_element.h \ - contributors.h sql_servers.h + contributors.h sql_servers.h \ + rpl_handler.h replication.h mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ @@ -120,7 +121,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ event_queue.cc event_db_repository.cc events.cc \ sql_plugin.cc sql_binlog.cc \ sql_builtin.cc sql_tablespace.cc partition_info.cc \ - sql_servers.cc event_parse_data.cc + sql_servers.cc event_parse_data.cc \ + rpl_handler.cc nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c diff --git a/sql/handler.cc b/sql/handler.cc index e5c64452aaf..f17bb9f8036 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -24,6 +24,7 @@ #endif #include "mysql_priv.h" +#include "rpl_handler.h" #include "rpl_filter.h" #include #include @@ -221,6 +222,8 @@ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type, return NULL; } + RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + switch (database_type) { #ifndef NO_HASH case DB_TYPE_HASH: @@ -1190,6 +1193,7 @@ int ha_commit_trans(THD *thd, bool all) if (cookie) tc_log->unlog(cookie, xid); DBUG_EXECUTE_IF("crash_commit_after", abort();); + RUN_HOOK(transaction, after_commit, (thd, FALSE)); end: if (rw_trans) start_waiting_global_read_lock(thd); @@ -1337,6 +1341,7 @@ int ha_rollback_trans(THD *thd, bool all) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); + RUN_HOOK(transaction, after_rollback, (thd, FALSE)); DBUG_RETURN(error); } @@ -1371,7 +1376,14 @@ int ha_autocommit_or_rollback(THD *thd, int error) thd->variables.tx_isolation=thd->session_tx_isolation; } + else #endif + { + if (!error) + RUN_HOOK(transaction, after_commit, (thd, FALSE)); + else + RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + } DBUG_RETURN(error); } diff --git a/sql/log.cc b/sql/log.cc index 1af2f3a4ddc..042431fc008 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -38,6 +38,7 @@ #endif #include +#include "rpl_handler.h" /* max size of the log message */ #define MAX_LOG_BUFFER_SIZE 1024 @@ -3683,9 +3684,11 @@ err: } -bool MYSQL_BIN_LOG::flush_and_sync() +bool MYSQL_BIN_LOG::flush_and_sync(bool *synced) { int err=0, fd=log_file.file; + if (synced) + *synced= 0; safe_mutex_assert_owner(&LOCK_log); if (flush_io_cache(&log_file)) return 1; @@ -3693,6 +3696,8 @@ bool MYSQL_BIN_LOG::flush_and_sync() { sync_binlog_counter= 0; err=my_sync(fd, MYF(MY_WME)); + if (synced) + *synced= 1; } return err; } @@ -3983,7 +3988,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, if (file == &log_file) { - error= flush_and_sync(); + error= flush_and_sync(0); if (!error) { signal_update(); @@ -4169,8 +4174,16 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) if (file == &log_file) // we are writing to the real log (disk) { - if (flush_and_sync()) + bool synced= 0; + if (flush_and_sync(&synced)) goto err; + + if (RUN_HOOK(binlog_storage, after_flush, + (thd, log_file_name, file->pos_in_file, synced))) { + sql_print_error("Failed to run 'after_flush' hooks"); + goto err; + } + signal_update(); rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); } @@ -4425,7 +4438,7 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log) DBUG_ASSERT(carry == 0); if (sync_log) - flush_and_sync(); + flush_and_sync(0); return 0; // All OK } @@ -4472,7 +4485,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) ev.write(&log_file); if (lock) { - if (!error && !(error= flush_and_sync())) + if (!error && !(error= flush_and_sync(0))) { signal_update(); rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); @@ -4560,7 +4573,8 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, if (incident && write_incident(thd, FALSE)) goto err; - if (flush_and_sync()) + bool synced= 0; + if (flush_and_sync(&synced)) goto err; DBUG_EXECUTE_IF("half_binlogged_transaction", abort();); if (cache->error) // Error on read @@ -4569,6 +4583,15 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, write_error=1; // Don't give more errors goto err; } + + if (RUN_HOOK(binlog_storage, after_flush, + (thd, log_file_name, log_file.pos_in_file, synced))) + { + sql_print_error("Failed to run 'after_flush' hooks"); + write_error=1; + goto err; + } + signal_update(); } diff --git a/sql/log.h b/sql/log.h index d306d6f7182..0550c921658 100644 --- a/sql/log.h +++ b/sql/log.h @@ -378,7 +378,21 @@ public: bool is_active(const char* log_file_name); int update_log_index(LOG_INFO* linfo, bool need_update_threads); void rotate_and_purge(uint flags); - bool flush_and_sync(); + + /** + Flush binlog cache and synchronize to disk. + + This function flushes events in binlog cache to binary log file, + it will do synchronizing according to the setting of system + variable 'sync_binlog'. If file is synchronized, @c synced will + be set to 1, otherwise 0. + + @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0 + + @retval 0 Success + @retval other Failure + */ + bool flush_and_sync(bool *synced); int purge_logs(const char *to_log, bool included, bool need_mutex, bool need_update_threads, ulonglong *decrease_log_space); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7e9eb6e7291..2ae4ec9e9b6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -31,6 +31,8 @@ #include "rpl_injector.h" +#include "rpl_handler.h" + #ifdef HAVE_SYS_PRCTL_H #include #endif @@ -1284,6 +1286,7 @@ void clean_up(bool print_message) ha_end(); if (tc_log) tc_log->close(); + delegates_destroy(); xid_cache_free(); delete_elements(&key_caches, (void (*)(const char*, uchar*)) free_key_cache); multi_keycache_free(); @@ -3760,6 +3763,13 @@ static int init_server_components() unireg_abort(1); } + /* initialize delegates for extension observers */ + if (delegates_init()) + { + sql_print_error("Initialize extension delegates failed"); + unireg_abort(1); + } + /* need to configure logging before initializing storage engines */ if (opt_update_log) { diff --git a/sql/replication.h b/sql/replication.h new file mode 100644 index 00000000000..6b7be58a5b1 --- /dev/null +++ b/sql/replication.h @@ -0,0 +1,490 @@ +/* Copyright (C) 2008 MySQL AB + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef REPLICATION_H +#define REPLICATION_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Transaction observer flags. +*/ +enum Trans_flags { + /** Transaction is a real transaction */ + TRANS_IS_REAL_TRANS = 1 +}; + +/** + Transaction observer parameter +*/ +typedef struct Trans_param { + uint32 server_id; + uint32 flags; + + /* + The latest binary log file name and position written by current + transaction, if binary log is disabled or no log event has been + written into binary log file by current transaction (events + written into transaction log cache are not counted), these two + member will be zero. + */ + const char *log_file; + my_off_t log_pos; +} Trans_param; + +/** + Observes and extends transaction execution +*/ +typedef struct Trans_observer { + uint32 len; + + /** + This callback is called after transaction commit + + This callback is called right after commit to storage engines for + transactional tables. + + For non-transactional tables, this is called at the end of the + statement, before sending statement status, if the statement + succeeded. + + @note The return value is currently ignored by the server. + + @param param The parameter for transaction observers + + @retval 0 Sucess + @retval 1 Failure + */ + int (*after_commit)(Trans_param *param); + + /** + This callback is called after transaction rollback + + This callback is called right after rollback to storage engines + for transactional tables. + + For non-transactional tables, this is called at the end of the + statement, before sending statement status, if the statement + failed. + + @note The return value is currently ignored by the server. + + @param param The parameter for transaction observers + + @retval 0 Sucess + @retval 1 Failure + */ + int (*after_rollback)(Trans_param *param); +} Trans_observer; + +/** + Binlog storage flags +*/ +enum Binlog_storage_flags { + /** Binary log was sync:ed */ + BINLOG_STORAGE_IS_SYNCED = 1 +}; + +/** + Binlog storage observer parameters + */ +typedef struct Binlog_storage_param { + uint32 server_id; +} Binlog_storage_param; + +/** + Observe binlog logging storage +*/ +typedef struct Binlog_storage_observer { + uint32 len; + + /** + This callback is called after binlog has been flushed + + This callback is called after cached events have been flushed to + binary log file. Whether the binary log file is synchronized to + disk is indicated by the bit BINLOG_STORAGE_IS_SYNCED in @a flags. + + @param param Observer common parameter + @param log_file Binlog file name been updated + @param log_pos Binlog position after update + @param flags flags for binlog storage + + @retval 0 Sucess + @retval 1 Failure + */ + int (*after_flush)(Binlog_storage_param *param, + const char *log_file, my_off_t log_pos, + uint32 flags); +} Binlog_storage_observer; + +/** + Replication binlog transmitter (binlog dump) observer parameter. +*/ +typedef struct Binlog_transmit_param { + uint32 server_id; + uint32 flags; +} Binlog_transmit_param; + +/** + Observe and extends the binlog dumping thread. +*/ +typedef struct Binlog_transmit_observer { + uint32 len; + + /** + This callback is called when binlog dumping starts + + + @param param Observer common parameter + @param log_file Binlog file name to transmit from + @param log_pos Binlog position to transmit from + + @retval 0 Sucess + @retval 1 Failure + */ + int (*transmit_start)(Binlog_transmit_param *param, + const char *log_file, my_off_t log_pos); + + /** + This callback is called when binlog dumping stops + + @param param Observer common parameter + + @retval 0 Sucess + @retval 1 Failure + */ + int (*transmit_stop)(Binlog_transmit_param *param); + + /** + This callback is called to reserve bytes in packet header for event transmission + + This callback is called when resetting transmit packet header to + reserve bytes for this observer in packet header. + + The @a header buffer is allocated by the server code, and @a size + is the size of the header buffer. Each observer can only reserve + a maximum size of @a size in the header. + + @param param Observer common parameter + @param header Pointer of the header buffer + @param size Size of the header buffer + @param len Header length reserved by this observer + + @retval 0 Sucess + @retval 1 Failure + */ + int (*reserve_header)(Binlog_transmit_param *param, + unsigned char *header, + unsigned long size, + unsigned long *len); + + /** + This callback is called before sending an event packet to slave + + @param param Observer common parameter + @param packet Binlog event packet to send + @param len Length of the event packet + @param log_file Binlog file name of the event packet to send + @param log_pos Binlog position of the event packet to send + + @retval 0 Sucess + @retval 1 Failure + */ + int (*before_send_event)(Binlog_transmit_param *param, + unsigned char *packet, unsigned long len, + const char *log_file, my_off_t log_pos ); + + /** + This callback is called after sending an event packet to slave + + @param param Observer common parameter + @param event_buf Binlog event packet buffer sent + @param len length of the event packet buffer + + @retval 0 Sucess + @retval 1 Failure + */ + int (*after_send_event)(Binlog_transmit_param *param, + const char *event_buf, unsigned long len); + + /** + This callback is called after resetting master status + + This is called when executing the command RESET MASTER, and is + used to reset status variables added by observers. + + @param param Observer common parameter + + @retval 0 Sucess + @retval 1 Failure + */ + int (*after_reset_master)(Binlog_transmit_param *param); +} Binlog_transmit_observer; + +/** + Binlog relay IO flags +*/ +enum Binlog_relay_IO_flags { + /** Binary relay log was sync:ed */ + BINLOG_RELAY_IS_SYNCED = 1 +}; + + +/** + Replication binlog relay IO observer parameter +*/ +typedef struct Binlog_relay_IO_param { + uint32 server_id; + + /* Master host, user and port */ + char *host; + char *user; + unsigned int port; + + char *master_log_name; + my_off_t master_log_pos; + + MYSQL *mysql; /* the connection to master */ +} Binlog_relay_IO_param; + +/** + Observes and extends the service of slave IO thread. +*/ +typedef struct Binlog_relay_IO_observer { + uint32 len; + + /** + This callback is called when slave IO thread starts + + @param param Observer common parameter + + @retval 0 Sucess + @retval 1 Failure + */ + int (*thread_start)(Binlog_relay_IO_param *param); + + /** + This callback is called when slave IO thread stops + + @param param Observer common parameter + + @retval 0 Sucess + @retval 1 Failure + */ + int (*thread_stop)(Binlog_relay_IO_param *param); + + /** + This callback is called before slave requesting binlog transmission from master + + This is called before slave issuing BINLOG_DUMP command to master + to request binlog. + + @param param Observer common parameter + @param flags binlog dump flags + + @retval 0 Sucess + @retval 1 Failure + */ + int (*before_request_transmit)(Binlog_relay_IO_param *param, uint32 flags); + + /** + This callback is called after read an event packet from master + + @param param Observer common parameter + @param packet The event packet read from master + @param len Length of the event packet read from master + @param event_buf The event packet return after process + @param event_len The length of event packet return after process + + @retval 0 Sucess + @retval 1 Failure + */ + int (*after_read_event)(Binlog_relay_IO_param *param, + const char *packet, unsigned long len, + const char **event_buf, unsigned long *event_len); + + /** + This callback is called after written an event packet to relay log + + @param param Observer common parameter + @param event_buf Event packet written to relay log + @param event_len Length of the event packet written to relay log + @param flags flags for relay log + + @retval 0 Sucess + @retval 1 Failure + */ + int (*after_queue_event)(Binlog_relay_IO_param *param, + const char *event_buf, unsigned long event_len, + uint32 flags); + + /** + This callback is called after reset slave relay log IO status + + @param param Observer common parameter + + @retval 0 Sucess + @retval 1 Failure + */ + int (*after_reset_slave)(Binlog_relay_IO_param *param); +} Binlog_relay_IO_observer; + + +/** + Register a transaction observer + + @param observer The transaction observer to register + @param p pointer to the internal plugin structure + + @retval 0 Sucess + @retval 1 Observer already exists +*/ +int register_trans_observer(Trans_observer *observer, void *p); + +/** + Unregister a transaction observer + + @param observer The transaction observer to unregister + @param p pointer to the internal plugin structure + + @retval 0 Sucess + @retval 1 Observer not exists +*/ +int unregister_trans_observer(Trans_observer *observer, void *p); + +/** + Register a binlog storage observer + + @param observer The binlog storage observer to register + @param p pointer to the internal plugin structure + + @retval 0 Sucess + @retval 1 Observer already exists +*/ +int register_binlog_storage_observer(Binlog_storage_observer *observer, void *p); + +/** + Unregister a binlog storage observer + + @param observer The binlog storage observer to unregister + @param p pointer to the internal plugin structure + + @retval 0 Sucess + @retval 1 Observer not exists +*/ +int unregister_binlog_storage_observer(Binlog_storage_observer *observer, void *p); + +/** + Register a binlog transmit observer + + @param observer The binlog transmit observer to register + @param p pointer to the internal plugin structure + + @retval 0 Sucess + @retval 1 Observer already exists +*/ +int register_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p); + +/** + Unregister a binlog transmit observer + + @param observer The binlog transmit observer to unregister + @param p pointer to the internal plugin structure + + @retval 0 Sucess + @retval 1 Observer not exists +*/ +int unregister_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p); + +/** + Register a binlog relay IO (slave IO thread) observer + + @param observer The binlog relay IO observer to register + @param p pointer to the internal plugin structure + + @retval 0 Sucess + @retval 1 Observer already exists +*/ +int register_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p); + +/** + Unregister a binlog relay IO (slave IO thread) observer + + @param observer The binlog relay IO observer to unregister + @param p pointer to the internal plugin structure + + @retval 0 Sucess + @retval 1 Observer not exists +*/ +int unregister_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p); + +/** + Connect to master + + This function can only used in the slave I/O thread context, and + will use the same master information to do the connection. + + @code + MYSQL *mysql = mysql_init(NULL); + if (rpl_connect_master(mysql)) + { + // do stuff with the connection + } + mysql_close(mysql); // close the connection + @endcode + + @param mysql address of MYSQL structure to use, pass NULL will + create a new one + + @return address of MYSQL structure on success, NULL on failure +*/ +MYSQL *rpl_connect_master(MYSQL *mysql); + +/** + Set thread entering a condition + + This function should be called before putting a thread to wait for + a condition. @a mutex should be held before calling this + function. After being waken up, @f thd_exit_cond should be called. + + @param thd The thread entering the condition, NULL means current thread + @param cond The condition the thread is going to wait for + @param mutex The mutex associated with the condition, this must be + held before call this function + @param msg The new process message for the thread +*/ +const char* thd_enter_cond(MYSQL_THD thd, pthread_cond_t *cond, + pthread_mutex_t *mutex, const char *msg); + +/** + Set thread leaving a condition + + This function should be called after a thread being waken up for a + condition. + + @param thd The thread entering the condition, NULL means current thread + @param old_msg The process message, ususally this should be the old process + message before calling @f thd_enter_cond +*/ +void thd_exit_cond(MYSQL_THD thd, const char *old_msg); + + +#ifdef __cplusplus +} +#endif +#endif /* REPLICATION_H */ diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc new file mode 100644 index 00000000000..aea838928b9 --- /dev/null +++ b/sql/rpl_handler.cc @@ -0,0 +1,493 @@ +/* Copyright (C) 2008 MySQL AB + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysql_priv.h" + +#include "rpl_mi.h" +#include "sql_repl.h" +#include "log_event.h" +#include "rpl_filter.h" +#include +#include "rpl_handler.h" + +Trans_delegate *transaction_delegate; +Binlog_storage_delegate *binlog_storage_delegate; +#ifdef HAVE_REPLICATION +Binlog_transmit_delegate *binlog_transmit_delegate; +Binlog_relay_IO_delegate *binlog_relay_io_delegate; +#endif /* HAVE_REPLICATION */ + +/* + structure to save transaction log filename and position +*/ +typedef struct Trans_binlog_info { + my_off_t log_pos; + 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) +{ + my_bool null_val; + user_var_entry *entry= + (user_var_entry*) hash_search(¤t_thd->user_vars, + (uchar*) name, strlen(name)); + if (!entry) + return 1; + *value= entry->val_int(&null_val); + if (null_value) + *null_value= null_val; + return 0; +} + +int get_user_var_real(const char *name, + double *value, int *null_value) +{ + my_bool null_val; + user_var_entry *entry= + (user_var_entry*) hash_search(¤t_thd->user_vars, + (uchar*) name, strlen(name)); + if (!entry) + return 1; + *value= entry->val_real(&null_val); + if (null_value) + *null_value= null_val; + return 0; +} + +int get_user_var_str(const char *name, char *value, + size_t len, unsigned int precision, int *null_value) +{ + String str; + my_bool null_val; + user_var_entry *entry= + (user_var_entry*) hash_search(¤t_thd->user_vars, + (uchar*) name, strlen(name)); + if (!entry) + return 1; + entry->val_str(&null_val, &str, precision); + strncpy(value, str.c_ptr(), len); + if (null_value) + *null_value= null_val; + return 0; +} + +int delegates_init() +{ + static unsigned char trans_mem[sizeof(Trans_delegate)]; + static unsigned char storage_mem[sizeof(Binlog_storage_delegate)]; +#ifdef HAVE_REPLICATION + static unsigned char transmit_mem[sizeof(Binlog_transmit_delegate)]; + static unsigned char relay_io_mem[sizeof(Binlog_relay_IO_delegate)]; +#endif + + if (!(transaction_delegate= new (trans_mem) Trans_delegate) + || (!transaction_delegate->is_inited()) + || !(binlog_storage_delegate= new (storage_mem) Binlog_storage_delegate) + || (!binlog_storage_delegate->is_inited()) +#ifdef HAVE_REPLICATION + || !(binlog_transmit_delegate= new (transmit_mem) Binlog_transmit_delegate) + || (!binlog_transmit_delegate->is_inited()) + || !(binlog_relay_io_delegate= new (relay_io_mem) Binlog_relay_IO_delegate) + || (!binlog_relay_io_delegate->is_inited()) +#endif /* HAVE_REPLICATION */ + ) + return 1; + + if (pthread_key_create(&RPL_TRANS_BINLOG_INFO, NULL)) + return 1; + return 0; +} + +void delegates_destroy() +{ + if (transaction_delegate) + transaction_delegate->~Trans_delegate(); + if (binlog_storage_delegate) + binlog_storage_delegate->~Binlog_storage_delegate(); +#ifdef HAVE_REPLICATION + if (binlog_transmit_delegate) + binlog_transmit_delegate->~Binlog_transmit_delegate(); + if (binlog_relay_io_delegate) + binlog_relay_io_delegate->~Binlog_relay_IO_delegate(); +#endif /* HAVE_REPLICATION */ +} + +/* + This macro is used by almost all the Delegate methods to iterate + over all the observers running given callback function of the + delegate . + + Add observer plugins to the thd->lex list, after each statement, all + plugins add to thd->lex will be automatically unlocked. + */ +#define FOREACH_OBSERVER(r, f, thd, args) \ + param.server_id= thd->server_id; \ + read_lock(); \ + Observer_info_iterator iter= observer_info_iter(); \ + Observer_info *info= iter++; \ + for (; info; info= iter++) \ + { \ + plugin_ref plugin= \ + my_plugin_lock(thd, &info->plugin); \ + if (!plugin) \ + { \ + r= 1; \ + break; \ + } \ + if (((Observer *)info->observer)->f \ + && ((Observer *)info->observer)->f args) \ + { \ + r= 1; \ + plugin_unlock(thd, plugin); \ + break; \ + } \ + plugin_unlock(thd, plugin); \ + } \ + unlock() + + +int Trans_delegate::after_commit(THD *thd, bool all) +{ + Trans_param param; + bool is_real_trans= (all || thd->transaction.all.ha_list == 0); + if (is_real_trans) + param.flags |= TRANS_IS_REAL_TRANS; + + 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; + param.log_pos= log_info ? log_info->log_pos : 0; + + int ret= 0; + FOREACH_OBSERVER(ret, after_commit, thd, (¶m)); + + /* + This is the end of a real transaction or autocommit statement, we + can free the memory allocated for binlog file and position. + */ + if (is_real_trans && log_info) + { + my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL); + my_free(log_info, MYF(0)); + } + return ret; +} + +int Trans_delegate::after_rollback(THD *thd, bool all) +{ + Trans_param param; + bool is_real_trans= (all || thd->transaction.all.ha_list == 0); + if (is_real_trans) + param.flags |= TRANS_IS_REAL_TRANS; + + 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; + param.log_pos= log_info ? log_info->log_pos : 0; + + int ret= 0; + FOREACH_OBSERVER(ret, after_commit, thd, (¶m)); + + /* + This is the end of a real transaction or autocommit statement, we + can free the memory allocated for binlog file and position. + */ + if (is_real_trans && log_info) + { + my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL); + my_free(log_info, MYF(0)); + } + return ret; +} + +int Binlog_storage_delegate::after_flush(THD *thd, + const char *log_file, + my_off_t log_pos, + bool synced) +{ + Binlog_storage_param param; + uint32 flags=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= + (Trans_binlog_info *)my_malloc(sizeof(Trans_binlog_info), MYF(0)))) + return 1; + my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_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, thd, + (¶m, log_info->log_file, log_info->log_pos, flags)); + return ret; +} + +#ifdef HAVE_REPLICATION +int Binlog_transmit_delegate::transmit_start(THD *thd, ushort flags, + const char *log_file, + my_off_t log_pos) +{ + Binlog_transmit_param param; + param.flags= flags; + + int ret= 0; + FOREACH_OBSERVER(ret, transmit_start, thd, (¶m, log_file, log_pos)); + return ret; +} + +int Binlog_transmit_delegate::transmit_stop(THD *thd, ushort flags) +{ + Binlog_transmit_param param; + param.flags= flags; + + int ret= 0; + FOREACH_OBSERVER(ret, transmit_stop, thd, (¶m)); + return ret; +} + +int Binlog_transmit_delegate::reserve_header(THD *thd, ushort flags, + String *packet) +{ + /* NOTE2ME: Maximum extra header size for each observer, I hope 32 + bytes should be enough for each Observer to reserve their extra + header. If later found this is not enough, we can increase this + /HEZX + */ +#define RESERVE_HEADER_SIZE 32 + unsigned char header[RESERVE_HEADER_SIZE]; + ulong hlen; + Binlog_transmit_param param; + param.flags= flags; + param.server_id= thd->server_id; + + int ret= 0; + read_lock(); + Observer_info_iterator iter= observer_info_iter(); + Observer_info *info= iter++; + for (; info; info= iter++) + { + plugin_ref plugin= + my_plugin_lock(thd, &info->plugin); + if (!plugin) + { + ret= 1; + break; + } + hlen= 0; + if (((Observer *)info->observer)->reserve_header + && ((Observer *)info->observer)->reserve_header(¶m, + header, + RESERVE_HEADER_SIZE, + &hlen)) + { + ret= 1; + plugin_unlock(thd, plugin); + break; + } + plugin_unlock(thd, plugin); + if (hlen == 0) + continue; + if (hlen > RESERVE_HEADER_SIZE || packet->append((char *)header, hlen)) + { + ret= 1; + break; + } + } + unlock(); + return ret; +} + +int Binlog_transmit_delegate::before_send_event(THD *thd, ushort flags, + String *packet, + const char *log_file, + my_off_t log_pos) +{ + Binlog_transmit_param param; + param.flags= flags; + + int ret= 0; + FOREACH_OBSERVER(ret, before_send_event, thd, + (¶m, (uchar *)packet->c_ptr(), + packet->length(), + log_file+dirname_length(log_file), log_pos)); + return ret; +} + +int Binlog_transmit_delegate::after_send_event(THD *thd, ushort flags, + String *packet) +{ + Binlog_transmit_param param; + param.flags= flags; + + int ret= 0; + FOREACH_OBSERVER(ret, after_send_event, thd, + (¶m, packet->c_ptr(), packet->length())); + return ret; +} + +int Binlog_transmit_delegate::after_reset_master(THD *thd, ushort flags) + +{ + Binlog_transmit_param param; + param.flags= flags; + + int ret= 0; + FOREACH_OBSERVER(ret, after_reset_master, thd, (¶m)); + return ret; +} + +void Binlog_relay_IO_delegate::init_param(Binlog_relay_IO_param *param, + Master_info *mi) +{ + param->mysql= mi->mysql; + param->user= mi->user; + param->host= mi->host; + param->port= mi->port; + param->master_log_name= mi->master_log_name; + param->master_log_pos= mi->master_log_pos; +} + +int Binlog_relay_IO_delegate::thread_start(THD *thd, Master_info *mi) +{ + Binlog_relay_IO_param param; + init_param(¶m, mi); + + int ret= 0; + FOREACH_OBSERVER(ret, thread_start, thd, (¶m)); + return ret; +} + + +int Binlog_relay_IO_delegate::thread_stop(THD *thd, Master_info *mi) +{ + + Binlog_relay_IO_param param; + init_param(¶m, mi); + + int ret= 0; + FOREACH_OBSERVER(ret, thread_stop, thd, (¶m)); + return ret; +} + +int Binlog_relay_IO_delegate::before_request_transmit(THD *thd, + Master_info *mi, + ushort flags) +{ + Binlog_relay_IO_param param; + init_param(¶m, mi); + + int ret= 0; + FOREACH_OBSERVER(ret, before_request_transmit, thd, (¶m, (uint32)flags)); + return ret; +} + +int Binlog_relay_IO_delegate::after_read_event(THD *thd, Master_info *mi, + const char *packet, ulong len, + const char **event_buf, + ulong *event_len) +{ + Binlog_relay_IO_param param; + init_param(¶m, mi); + + int ret= 0; + FOREACH_OBSERVER(ret, after_read_event, thd, + (¶m, packet, len, event_buf, event_len)); + return ret; +} + +int Binlog_relay_IO_delegate::after_queue_event(THD *thd, Master_info *mi, + const char *event_buf, + ulong event_len, + bool synced) +{ + Binlog_relay_IO_param param; + init_param(¶m, mi); + + uint32 flags=0; + if (synced) + flags |= BINLOG_STORAGE_IS_SYNCED; + + int ret= 0; + FOREACH_OBSERVER(ret, after_queue_event, thd, + (¶m, event_buf, event_len, flags)); + return ret; +} + +int Binlog_relay_IO_delegate::after_reset_slave(THD *thd, Master_info *mi) + +{ + Binlog_relay_IO_param param; + init_param(¶m, mi); + + int ret= 0; + FOREACH_OBSERVER(ret, after_reset_slave, thd, (¶m)); + return ret; +} +#endif /* HAVE_REPLICATION */ + +int register_trans_observer(Trans_observer *observer, void *p) +{ + return transaction_delegate->add_observer(observer, (st_plugin_int *)p); +} + +int unregister_trans_observer(Trans_observer *observer, void *p) +{ + return transaction_delegate->remove_observer(observer, (st_plugin_int *)p); +} + +int register_binlog_storage_observer(Binlog_storage_observer *observer, void *p) +{ + return binlog_storage_delegate->add_observer(observer, (st_plugin_int *)p); +} + +int unregister_binlog_storage_observer(Binlog_storage_observer *observer, void *p) +{ + return binlog_storage_delegate->remove_observer(observer, (st_plugin_int *)p); +} + +#ifdef HAVE_REPLICATION +int register_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p) +{ + return binlog_transmit_delegate->add_observer(observer, (st_plugin_int *)p); +} + +int unregister_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p) +{ + return binlog_transmit_delegate->remove_observer(observer, (st_plugin_int *)p); +} + +int register_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p) +{ + return binlog_relay_io_delegate->add_observer(observer, (st_plugin_int *)p); +} + +int unregister_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p) +{ + return binlog_relay_io_delegate->remove_observer(observer, (st_plugin_int *)p); +} +#endif /* HAVE_REPLICATION */ diff --git a/sql/rpl_handler.h b/sql/rpl_handler.h new file mode 100644 index 00000000000..4fb7b4e035b --- /dev/null +++ b/sql/rpl_handler.h @@ -0,0 +1,213 @@ +/* Copyright (C) 2008 MySQL AB + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef RPL_HANDLER_H +#define RPL_HANDLER_H + +#include "mysql_priv.h" +#include "rpl_mi.h" +#include "rpl_rli.h" +#include "sql_plugin.h" +#include "replication.h" + +class Observer_info { +public: + void *observer; + st_plugin_int *plugin_int; + plugin_ref plugin; + + Observer_info(void *ob, st_plugin_int *p) + :observer(ob), plugin_int(p) + { + plugin= plugin_int_to_ref(plugin_int); + } +}; + +class Delegate { +public: + typedef List Observer_info_list; + typedef List_iterator Observer_info_iterator; + + int add_observer(void *observer, st_plugin_int *plugin) + { + int ret= FALSE; + if (!inited) + return TRUE; + write_lock(); + Observer_info_iterator iter(observer_info_list); + Observer_info *info= iter++; + while (info && info->observer != observer) + info= iter++; + if (!info) + { + info= new Observer_info(observer, plugin); + if (!info || observer_info_list.push_back(info, &memroot)) + ret= TRUE; + } + else + ret= TRUE; + unlock(); + return ret; + } + + int remove_observer(void *observer, st_plugin_int *plugin) + { + int ret= FALSE; + if (!inited) + return TRUE; + write_lock(); + Observer_info_iterator iter(observer_info_list); + Observer_info *info= iter++; + while (info && info->observer != observer) + info= iter++; + if (info) + iter.remove(); + else + ret= TRUE; + unlock(); + return ret; + } + + inline Observer_info_iterator observer_info_iter() + { + return Observer_info_iterator(observer_info_list); + } + + inline bool is_empty() + { + return observer_info_list.is_empty(); + } + + inline int read_lock() + { + if (!inited) + return TRUE; + return rw_rdlock(&lock); + } + + inline int write_lock() + { + if (!inited) + return TRUE; + return rw_wrlock(&lock); + } + + inline int unlock() + { + if (!inited) + return TRUE; + return rw_unlock(&lock); + } + + inline bool is_inited() + { + return inited; + } + + Delegate() + { + inited= FALSE; + if (my_rwlock_init(&lock, NULL)) + return; + init_sql_alloc(&memroot, 1024, 0); + inited= TRUE; + } + ~Delegate() + { + inited= FALSE; + rwlock_destroy(&lock); + free_root(&memroot, MYF(0)); + } + +private: + Observer_info_list observer_info_list; + rw_lock_t lock; + MEM_ROOT memroot; + bool inited; +}; + +class Trans_delegate + :public Delegate { +public: + typedef Trans_observer Observer; + int before_commit(THD *thd, bool all); + int before_rollback(THD *thd, bool all); + int after_commit(THD *thd, bool all); + int after_rollback(THD *thd, bool all); +}; + +class Binlog_storage_delegate + :public Delegate { +public: + typedef Binlog_storage_observer Observer; + int after_flush(THD *thd, const char *log_file, + my_off_t log_pos, bool synced); +}; + +#ifdef HAVE_REPLICATION +class Binlog_transmit_delegate + :public Delegate { +public: + typedef Binlog_transmit_observer Observer; + int transmit_start(THD *thd, ushort flags, + const char *log_file, my_off_t log_pos); + int transmit_stop(THD *thd, ushort flags); + int reserve_header(THD *thd, ushort flags, String *packet); + int before_send_event(THD *thd, ushort flags, + String *packet, const + char *log_file, my_off_t log_pos ); + int after_send_event(THD *thd, ushort flags, + String *packet); + int after_reset_master(THD *thd, ushort flags); +}; + +class Binlog_relay_IO_delegate + :public Delegate { +public: + typedef Binlog_relay_IO_observer Observer; + int thread_start(THD *thd, Master_info *mi); + int thread_stop(THD *thd, Master_info *mi); + int before_request_transmit(THD *thd, Master_info *mi, ushort flags); + int after_read_event(THD *thd, Master_info *mi, + const char *packet, ulong len, + const char **event_buf, ulong *event_len); + int after_queue_event(THD *thd, Master_info *mi, + const char *event_buf, ulong event_len, + bool synced); + int after_reset_slave(THD *thd, Master_info *mi); +private: + void init_param(Binlog_relay_IO_param *param, Master_info *mi); +}; +#endif /* HAVE_REPLICATION */ + +int delegates_init(); +void delegates_destroy(); + +extern Trans_delegate *transaction_delegate; +extern Binlog_storage_delegate *binlog_storage_delegate; +#ifdef HAVE_REPLICATION +extern Binlog_transmit_delegate *binlog_transmit_delegate; +extern Binlog_relay_IO_delegate *binlog_relay_io_delegate; +#endif /* HAVE_REPLICATION */ + +/* + if there is no observers in the delegate, we can return 0 + immediately. +*/ +#define RUN_HOOK(group, hook, args) \ + (group ##_delegate->is_empty() ? \ + 0 : group ##_delegate->hook args) + +#endif /* RPL_HANDLER_H */ diff --git a/sql/slave.cc b/sql/slave.cc index fac9ee214c5..4988886dce4 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -40,6 +40,7 @@ #include #include #include +#include "rpl_handler.h" #ifdef HAVE_REPLICATION @@ -69,6 +70,8 @@ ulonglong relay_log_space_limit = 0; int disconnect_slave_event_count = 0, abort_slave_event_count = 0; int events_till_abort = -1; +static pthread_key(Master_info*, RPL_MASTER_INFO); + enum enum_slave_reconnect_actions { SLAVE_RECON_ACT_REG= 0, @@ -231,6 +234,10 @@ int init_slave() TODO: re-write this to interate through the list of files for multi-master */ + + if (pthread_key_create(&RPL_MASTER_INFO, NULL)) + goto err; + active_mi= new Master_info; /* @@ -1868,17 +1875,22 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed, } -static int request_dump(MYSQL* mysql, Master_info* mi, - bool *suppress_warnings) +static int request_dump(THD *thd, MYSQL* mysql, Master_info* mi, + bool *suppress_warnings) { uchar buf[FN_REFLEN + 10]; int len; - int binlog_flags = 0; // for now + ushort binlog_flags = 0; // for now char* logname = mi->master_log_name; DBUG_ENTER("request_dump"); *suppress_warnings= FALSE; + if (RUN_HOOK(binlog_relay_io, + before_request_transmit, + (thd, mi, binlog_flags))) + DBUG_RETURN(1); + // TODO if big log files: Change next to int8store() int4store(buf, (ulong) mi->master_log_pos); int2store(buf + 4, binlog_flags); @@ -2532,6 +2544,16 @@ pthread_handler_t handle_slave_io(void *arg) mi->master_log_name, llstr(mi->master_log_pos,llbuff))); + /* This must be called before run any binlog_relay_io hooks */ + my_pthread_setspecific_ptr(RPL_MASTER_INFO, mi); + + if (RUN_HOOK(binlog_relay_io, thread_start, (thd, mi))) + { + mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER(ER_SLAVE_FATAL_ERROR), "Failed to run 'thread_start' hook"); + goto err; + } + if (!(mi->mysql = mysql = mysql_init(NULL))) { mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, @@ -2621,7 +2643,7 @@ connected: while (!io_slave_killed(thd,mi)) { thd_proc_info(thd, "Requesting binlog dump"); - if (request_dump(mysql, mi, &suppress_warnings)) + if (request_dump(thd, mysql, mi, &suppress_warnings)) { sql_print_error("Failed on request_dump()"); if (check_io_slave_killed(thd, mi, "Slave I/O thread killed while \ @@ -2641,6 +2663,7 @@ requesting master dump") || goto err; goto connected; }); + const char *event_buf; DBUG_ASSERT(mi->last_error().number == 0); while (!io_slave_killed(thd,mi)) @@ -2697,14 +2720,37 @@ Stopping slave I/O thread due to out-of-memory error from master"); retry_count=0; // ok event, reset retry counter thd_proc_info(thd, "Queueing master event to the relay log"); - if (queue_event(mi,(const char*)mysql->net.read_pos + 1, - event_len)) + event_buf= (const char*)mysql->net.read_pos + 1; + if (RUN_HOOK(binlog_relay_io, after_read_event, + (thd, mi,(const char*)mysql->net.read_pos + 1, + event_len, &event_buf, &event_len))) + { + mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER(ER_SLAVE_FATAL_ERROR), + "Failed to run 'after_read_event' hook"); + goto err; + } + + /* XXX: 'synced' should be updated by queue_event to indicate + whether event has been synced to disk */ + bool synced= 0; + if (queue_event(mi, event_buf, event_len)) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), "could not queue event from master"); goto err; } + + if (RUN_HOOK(binlog_relay_io, after_queue_event, + (thd, mi, event_buf, event_len, synced))) + { + mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER(ER_SLAVE_FATAL_ERROR), + "Failed to run 'after_queue_event' hook"); + goto err; + } + if (flush_master_info(mi, 1)) { sql_print_error("Failed to flush master info file"); @@ -2750,6 +2796,7 @@ err: // print the current replication position sql_print_information("Slave I/O thread exiting, read up to log '%s', position %s", IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff)); + RUN_HOOK(binlog_relay_io, thread_stop, (thd, mi)); thd->set_query(NULL, 0); thd->reset_db(NULL, 0); if (mysql) @@ -3906,6 +3953,71 @@ static int safe_reconnect(THD* thd, MYSQL* mysql, Master_info* mi, } +MYSQL *rpl_connect_master(MYSQL *mysql) +{ + THD *thd= current_thd; + Master_info *mi= my_pthread_getspecific_ptr(Master_info*, RPL_MASTER_INFO); + if (!mi) + { + sql_print_error("'rpl_connect_master' must be called in slave I/O thread context."); + return NULL; + } + + bool allocated= false; + + if (!mysql) + { + if(!(mysql= mysql_init(NULL))) + { + sql_print_error("rpl_connect_master: failed in mysql_init()"); + return NULL; + } + allocated= true; + } + + /* + XXX: copied from connect_to_master, this function should not + change the slave status, so we cannot use connect_to_master + directly + + TODO: make this part a seperate function to eliminate duplication + */ + mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout); + mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout); + +#ifdef HAVE_OPENSSL + if (mi->ssl) + { + mysql_ssl_set(mysql, + mi->ssl_key[0]?mi->ssl_key:0, + mi->ssl_cert[0]?mi->ssl_cert:0, + mi->ssl_ca[0]?mi->ssl_ca:0, + mi->ssl_capath[0]?mi->ssl_capath:0, + mi->ssl_cipher[0]?mi->ssl_cipher:0); + mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, + &mi->ssl_verify_server_cert); + } +#endif + + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname); + /* This one is not strictly needed but we have it here for completeness */ + mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir); + + if (io_slave_killed(thd, mi) + || !mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0, + mi->port, 0, 0)) + { + if (!io_slave_killed(thd, mi)) + sql_print_error("rpl_connect_master: error connecting to master: %s (server_error: %d)", + mysql_error(mysql), mysql_errno(mysql)); + + if (allocated) + mysql_close(mysql); // this will free the object + return NULL; + } + return mysql; +} + /* Store the file and position where the execute-slave thread are in the relay log. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 3f568566c89..755e60b4fc2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -277,6 +277,42 @@ const char *set_thd_proc_info(THD *thd, const char *info, return old_info; } +extern "C" +const char* thd_enter_cond(MYSQL_THD thd, pthread_cond_t *cond, + pthread_mutex_t *mutex, const char *msg) +{ + if (!thd) + thd= current_thd; + + const char* old_msg = thd->proc_info; + safe_mutex_assert_owner(mutex); + thd->mysys_var->current_mutex = mutex; + thd->mysys_var->current_cond = cond; + thd->proc_info = msg; + return old_msg; +} + +extern "C" +void thd_exit_cond(MYSQL_THD thd, const char *old_msg) +{ + if (!thd) + thd= current_thd; + + /* + Putting the mutex unlock in thd_exit_cond() ensures that + mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is + locked (if that would not be the case, you'll get a deadlock if someone + does a THD::awake() on you). + */ + pthread_mutex_unlock(thd->mysys_var->current_mutex); + pthread_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex = 0; + thd->mysys_var->current_cond = 0; + thd->proc_info = old_msg; + pthread_mutex_unlock(&thd->mysys_var->mutex); + return; +} + extern "C" void **thd_ha_data(const THD *thd, const struct handlerton *hton) { diff --git a/sql/sql_class.h b/sql/sql_class.h index f52d5fae76f..3d7ff0ca0a1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -22,6 +22,7 @@ #include "log.h" #include "rpl_tblmap.h" +#include "replication.h" /** An interface that is used to take an action when @@ -1940,27 +1941,11 @@ public: inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex, const char* msg) { - const char* old_msg = proc_info; - safe_mutex_assert_owner(mutex); - mysys_var->current_mutex = mutex; - mysys_var->current_cond = cond; - proc_info = msg; - return old_msg; + return thd_enter_cond(this, cond, mutex, msg); } inline void exit_cond(const char* old_msg) { - /* - Putting the mutex unlock in exit_cond() ensures that - mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is - locked (if that would not be the case, you'll get a deadlock if someone - does a THD::awake() on you). - */ - pthread_mutex_unlock(mysys_var->current_mutex); - pthread_mutex_lock(&mysys_var->mutex); - mysys_var->current_mutex = 0; - mysys_var->current_cond = 0; - proc_info = old_msg; - pthread_mutex_unlock(&mysys_var->mutex); + thd_exit_cond(this, old_msg); } inline time_t query_start() { query_start_used=1; return start_time; } inline void set_time() diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ca27d476213..6019c385fb8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -21,6 +21,7 @@ #include #include #include +#include "rpl_handler.h" #include "sp_head.h" #include "sp.h" diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index da168d36429..8cf8c4cb81f 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -19,14 +19,6 @@ #define REPORT_TO_LOG 1 #define REPORT_TO_USER 2 -#ifdef DBUG_OFF -#define plugin_ref_to_int(A) A -#define plugin_int_to_ref(A) A -#else -#define plugin_ref_to_int(A) (A ? A[0] : NULL) -#define plugin_int_to_ref(A) &(A) -#endif - extern struct st_mysql_plugin *mysqld_builtins[]; /** @@ -54,7 +46,8 @@ const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]= { C_STRING_WITH_LEN("STORAGE ENGINE") }, { C_STRING_WITH_LEN("FTPARSER") }, { C_STRING_WITH_LEN("DAEMON") }, - { C_STRING_WITH_LEN("INFORMATION SCHEMA") } + { C_STRING_WITH_LEN("INFORMATION SCHEMA") }, + { C_STRING_WITH_LEN("REPLICATION") }, }; extern int initialize_schema_table(st_plugin_int *plugin); @@ -93,7 +86,8 @@ static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= MYSQL_HANDLERTON_INTERFACE_VERSION, MYSQL_FTPARSER_INTERFACE_VERSION, MYSQL_DAEMON_INTERFACE_VERSION, - MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION + MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION, + MYSQL_REPLICATION_INTERFACE_VERSION, }; static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= { @@ -101,7 +95,8 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= MYSQL_HANDLERTON_INTERFACE_VERSION, MYSQL_FTPARSER_INTERFACE_VERSION, MYSQL_DAEMON_INTERFACE_VERSION, - MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION + MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION, + MYSQL_REPLICATION_INTERFACE_VERSION, }; static bool initialized= 0; diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 004d0d5abb7..c6ad846943c 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -18,6 +18,14 @@ class sys_var; +#ifdef DBUG_OFF +#define plugin_ref_to_int(A) A +#define plugin_int_to_ref(A) A +#else +#define plugin_ref_to_int(A) (A ? A[0] : NULL) +#define plugin_int_to_ref(A) &(A) +#endif + /* the following flags are valid for plugin_init() */ diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 0ec8d91214c..671f6785640 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -21,6 +21,7 @@ #include "log_event.h" #include "rpl_filter.h" #include +#include "rpl_handler.h" int max_binlog_dump_events = 0; // unlimited my_bool opt_sporadic_binlog_dump_fail = 0; @@ -80,6 +81,32 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name, DBUG_RETURN(0); } +/* + Reset thread transmit packet buffer for event sending + + This function allocates header bytes for event transmission, and + should be called before store the event data to the packet buffer. +*/ +static int reset_transmit_packet(THD *thd, ushort flags, + ulong *ev_offset, const char **errmsg) +{ + int ret= 0; + String *packet= &thd->packet; + + /* reserve and set default header */ + packet->length(0); + packet->set("\0", 1, &my_charset_bin); + + if (RUN_HOOK(binlog_transmit, reserve_header, (thd, flags, packet))) + { + *errmsg= "Failed to run hook 'reserve_header'"; + my_errno= ER_UNKNOWN_ERROR; + ret= 1; + } + *ev_offset= packet->length(); + return ret; +} + static int send_file(THD *thd) { NET* net = &thd->net; @@ -346,6 +373,9 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, LOG_INFO linfo; char *log_file_name = linfo.log_file_name; char search_file_name[FN_REFLEN], *name; + + ulong ev_offset; + IO_CACHE log; File file = -1; String* packet = &thd->packet; @@ -361,6 +391,14 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, DBUG_PRINT("enter",("log_ident: '%s' pos: %ld", log_ident, (long) pos)); bzero((char*) &log,sizeof(log)); + sql_print_information("Start binlog_dump to slave_server(%d), pos(%s, %lu)", + thd->server_id, log_ident, (ulong)pos); + if (RUN_HOOK(binlog_transmit, transmit_start, (thd, flags, log_ident, pos))) + { + errmsg= "Failed to run hook 'transmit_start'"; + my_errno= ER_UNKNOWN_ERROR; + goto err; + } #ifndef DBUG_OFF if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2)) @@ -416,11 +454,9 @@ impossible position"; goto err; } - /* - We need to start a packet with something other than 255 - to distinguish it from error - */ - packet->set("\0", 1, &my_charset_bin); /* This is the start of a new packet */ + /* reset transmit packet for the fake rotate event below */ + if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) + goto err; /* Tell the client about the log name with a fake Rotate event; @@ -460,7 +496,7 @@ impossible position"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; } - packet->set("\0", 1, &my_charset_bin); + /* Adding MAX_LOG_EVENT_HEADER_LEN, since a binlog event can become this larger than the corresponding packet (query) sent @@ -476,6 +512,11 @@ impossible position"; log_lock = mysql_bin_log.get_log_lock(); if (pos > BIN_LOG_HEADER_SIZE) { + /* reset transmit packet for the event read from binary log + file */ + if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) + goto err; + /* Try to find a Format_description_log_event at the beginning of the binlog @@ -483,29 +524,30 @@ impossible position"; if (!(error = Log_event::read_log_event(&log, packet, log_lock))) { /* - The packet has offsets equal to the normal offsets in a binlog - event +1 (the first character is \0). + The packet has offsets equal to the normal offsets in a + binlog event + ev_offset (the first ev_offset characters are + the header (default \0)). */ DBUG_PRINT("info", ("Looked for a Format_description_log_event, found event type %d", - (*packet)[EVENT_TYPE_OFFSET+1])); - if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT) + (*packet)[EVENT_TYPE_OFFSET+ev_offset])); + if ((*packet)[EVENT_TYPE_OFFSET+ev_offset] == FORMAT_DESCRIPTION_EVENT) { - binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] & + binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+ev_offset] & LOG_EVENT_BINLOG_IN_USE_F); - (*packet)[FLAGS_OFFSET+1] &= ~LOG_EVENT_BINLOG_IN_USE_F; + (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F; /* mark that this event with "log_pos=0", so the slave should not increment master's binlog position (rli->group_master_log_pos) */ - int4store((char*) packet->ptr()+LOG_POS_OFFSET+1, 0); + int4store((char*) packet->ptr()+LOG_POS_OFFSET+ev_offset, 0); /* if reconnect master sends FD event with `created' as 0 to avoid destroying temp tables. */ int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+ - ST_CREATED_OFFSET+1, (ulong) 0); + ST_CREATED_OFFSET+ev_offset, (ulong) 0); /* send it */ if (my_net_write(net, (uchar*) packet->ptr(), packet->length())) { @@ -531,8 +573,6 @@ impossible position"; Format_description_log_event will be found naturally if it is written. */ } - /* reset the packet as we wrote to it in any case */ - packet->set("\0", 1, &my_charset_bin); } /* end of if (pos > BIN_LOG_HEADER_SIZE); */ else { @@ -544,6 +584,12 @@ impossible position"; while (!net->error && net->vio != 0 && !thd->killed) { + Log_event_type event_type= UNKNOWN_EVENT; + + /* reset the transmit packet for the event read from binary log + file */ + if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) + goto err; while (!(error = Log_event::read_log_event(&log, packet, log_lock))) { #ifndef DBUG_OFF @@ -556,15 +602,25 @@ impossible position"; } #endif - if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT) + event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]); + if (event_type == FORMAT_DESCRIPTION_EVENT) { - binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] & + binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+ev_offset] & LOG_EVENT_BINLOG_IN_USE_F); - (*packet)[FLAGS_OFFSET+1] &= ~LOG_EVENT_BINLOG_IN_USE_F; + (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F; } - else if ((*packet)[EVENT_TYPE_OFFSET+1] == STOP_EVENT) + else if (event_type == STOP_EVENT) binlog_can_be_corrupted= FALSE; + pos = my_b_tell(&log); + if (RUN_HOOK(binlog_transmit, before_send_event, + (thd, flags, packet, log_file_name, pos))) + { + my_errno= ER_UNKNOWN_ERROR; + errmsg= "run 'before_send_event' hook failed"; + goto err; + } + if (my_net_write(net, (uchar*) packet->ptr(), packet->length())) { errmsg = "Failed on my_net_write()"; @@ -572,9 +628,8 @@ impossible position"; goto err; } - DBUG_PRINT("info", ("log event code %d", - (*packet)[LOG_EVENT_OFFSET+1] )); - if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) + DBUG_PRINT("info", ("log event code %d", event_type)); + if (event_type == LOAD_EVENT) { if (send_file(thd)) { @@ -583,7 +638,17 @@ impossible position"; goto err; } } - packet->set("\0", 1, &my_charset_bin); + + if (RUN_HOOK(binlog_transmit, after_send_event, (thd, flags, packet))) + { + errmsg= "Failed to run hook 'after_send_event'"; + my_errno= ER_UNKNOWN_ERROR; + goto err; + } + + /* reset transmit packet for next loop */ + if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) + goto err; } /* @@ -634,6 +699,11 @@ impossible position"; } #endif + /* reset the transmit packet for the event read from binary log + file */ + if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) + goto err; + /* No one will update the log while we are reading now, but we'll be quick and just read one record @@ -650,6 +720,7 @@ impossible position"; /* we read successfully, so we'll need to send it to the slave */ pthread_mutex_unlock(log_lock); read_packet = 1; + event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]); break; case LOG_READ_EOF: @@ -676,8 +747,17 @@ impossible position"; } if (read_packet) - { - thd_proc_info(thd, "Sending binlog event to slave"); + { + thd_proc_info(thd, "Sending binlog event to slave"); + pos = my_b_tell(&log); + if (RUN_HOOK(binlog_transmit, before_send_event, + (thd, flags, packet, log_file_name, pos))) + { + my_errno= ER_UNKNOWN_ERROR; + errmsg= "run 'before_send_event' hook failed"; + goto err; + } + if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) ) { errmsg = "Failed on my_net_write()"; @@ -685,7 +765,7 @@ impossible position"; goto err; } - if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) + if (event_type == LOAD_EVENT) { if (send_file(thd)) { @@ -694,11 +774,13 @@ impossible position"; goto err; } } - packet->set("\0", 1, &my_charset_bin); - /* - No need to net_flush because we will get to flush later when - we hit EOF pretty quick - */ + + if (RUN_HOOK(binlog_transmit, after_send_event, (thd, flags, packet))) + { + my_errno= ER_UNKNOWN_ERROR; + errmsg= "Failed to run hook 'after_send_event'"; + goto err; + } } if (fatal_error) @@ -734,6 +816,10 @@ impossible position"; end_io_cache(&log); (void) my_close(file, MYF(MY_WME)); + /* reset transmit packet for the possible fake rotate event */ + if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) + goto err; + /* Call fake_rotate_event() in case the previous log (the one which we have just finished reading) did not contain a Rotate event @@ -750,9 +836,6 @@ impossible position"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; } - - packet->length(0); - packet->append('\0'); } } @@ -760,6 +843,7 @@ end: end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); + RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags)); my_eof(thd); thd_proc_info(thd, "Waiting to finalize termination"); pthread_mutex_lock(&LOCK_thread_count); @@ -770,6 +854,7 @@ end: err: thd_proc_info(thd, "Waiting to finalize termination"); end_io_cache(&log); + RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags)); /* Exclude iteration through thread list this is needed for purge_logs() - it will iterate through @@ -1064,6 +1149,7 @@ int reset_slave(THD *thd, Master_info* mi) goto err; } + RUN_HOOK(binlog_relay_io, after_reset_slave, (thd, mi)); err: unlock_slave_threads(mi); if (error) @@ -1363,7 +1449,11 @@ int reset_master(THD* thd) ER(ER_FLUSH_MASTER_BINLOG_CLOSED), MYF(ME_BELL+ME_WAITTANG)); return 1; } - return mysql_bin_log.reset_logs(thd); + + if (mysql_bin_log.reset_logs(thd)) + return 1; + RUN_HOOK(binlog_transmit, after_reset_master, (thd, 0 /* flags */)); + return 0; } int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1, @@ -1836,5 +1926,3 @@ int init_replication_sys_vars() } #endif /* HAVE_REPLICATION */ - - From a8edd0aabb5059935b99076fbcc92403079535df Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Mon, 28 Sep 2009 00:54:22 +0400 Subject: [PATCH 018/274] Update default.conf. --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index 172fa24692b..771201a109b 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.4.5-next-windows-enhancements" +tree_name = "mysql-5.4.5-next-mr" From 2118bd104c4dd7c2aab0b80fa7053d8a491a90c4 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 28 Sep 2009 10:21:25 +0300 Subject: [PATCH 019/274] Ported WL#3220 to mysql-next-mr. --- mysql-test/mysql-test-run.pl | 1 - mysql-test/r/bench_count_distinct.result | 2 +- mysql-test/r/group_min_max.result | 270 ++++- mysql-test/t/group_min_max.test | 125 ++- sql/field.h | 9 +- sql/item_sum.cc | 1201 +++++++++++----------- sql/item_sum.h | 535 ++++++---- sql/opt_range.cc | 188 +++- sql/opt_range.h | 17 +- sql/opt_sum.cc | 10 +- sql/sql_class.h | 1 + sql/sql_select.cc | 130 ++- sql/sql_select.h | 7 + sql/sql_yacc.yy | 6 +- 14 files changed, 1620 insertions(+), 882 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 83364db0eeb..17102196f42 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -5085,7 +5085,6 @@ sub valgrind_arguments { else { mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option - mtr_add_arg($args, "--alignment=8"); mtr_add_arg($args, "--leak-check=yes"); mtr_add_arg($args, "--num-callers=16"); mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) diff --git a/mysql-test/r/bench_count_distinct.result b/mysql-test/r/bench_count_distinct.result index 79e12afd237..8b67e4be38a 100644 --- a/mysql-test/r/bench_count_distinct.result +++ b/mysql-test/r/bench_count_distinct.result @@ -5,7 +5,7 @@ count(distinct n) 100 explain extended select count(distinct n) from t1; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 index NULL n 4 NULL 200 100.00 Using index +1 SIMPLE t1 range NULL n 4 NULL 10 100.00 Using index for group-by Warnings: Note 1003 select count(distinct `test`.`t1`.`n`) AS `count(distinct n)` from `test`.`t1` drop table t1; diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index ac9a53ca238..c4841ee57a0 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -1800,23 +1800,23 @@ b a explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 65 Using where; Using index for group-by (scanning) explain extended select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 128 75.00 Using where; Using index +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 100.00 Using where; Using index for group-by Warnings: Note 1003 select count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`) AS `count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`b` = 'c') and (`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a')) explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index -explain extended select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); +explain extended select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 128 75.00 Using where; Using index +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 100.00 Using where; Using index for group-by Warnings: -Note 1003 select (ord(`test`.`t1`.`a1`) + count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`)) AS `ord(a1) + count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a')) +Note 1003 select (98 + count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`)) AS `98 + count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a')) select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); count(distinct a1,a2,b) 4 @@ -1829,8 +1829,8 @@ count(distinct a1,a2,b) select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a'); count(distinct b) 1 -select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); -ord(a1) + count(distinct a1,a2,b) +select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); +98 + count(distinct a1,a2,b) 104 explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra @@ -2514,3 +2514,257 @@ a MAX(b) 2 1 DROP TABLE t; End of 5.1 tests +# +# WL#3220 (Loose index scan for COUNT DISTINCT) +# +CREATE TABLE t1 (a INT, b INT, c INT, KEY (a,b)); +INSERT INTO t1 VALUES (1,1,1), (1,2,1), (1,3,1), (1,4,1); +INSERT INTO t1 SELECT a, b + 4, 1 FROM t1; +INSERT INTO t1 SELECT a + 1, b, 1 FROM t1; +CREATE TABLE t2 (a INT, b INT, c INT, d INT, e INT, f INT, KEY (a,b,c)); +INSERT INTO t2 VALUES (1,1,1,1,1,1), (1,2,1,1,1,1), (1,3,1,1,1,1), +(1,4,1,1,1,1); +INSERT INTO t2 SELECT a, b + 4, c,d,e,f FROM t2; +INSERT INTO t2 SELECT a + 1, b, c,d,e,f FROM t2; +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT a) FROM t1; +COUNT(DISTINCT a) +2 +EXPLAIN SELECT COUNT(DISTINCT a,b) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT a,b) FROM t1; +COUNT(DISTINCT a,b) +16 +EXPLAIN SELECT COUNT(DISTINCT b,a) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT b,a) FROM t1; +COUNT(DISTINCT b,a) +16 +EXPLAIN SELECT COUNT(DISTINCT b) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 10 NULL 16 Using index +SELECT COUNT(DISTINCT b) FROM t1; +COUNT(DISTINCT b) +8 +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a; +COUNT(DISTINCT a) +1 +1 +EXPLAIN SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a; +COUNT(DISTINCT b) +8 +8 +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 10 NULL 16 Using index; Using filesort +SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b; +COUNT(DISTINCT a) +2 +2 +2 +2 +2 +2 +2 +2 +EXPLAIN SELECT DISTINCT COUNT(DISTINCT a) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 10 NULL 16 Using index +SELECT DISTINCT COUNT(DISTINCT a) FROM t1; +COUNT(DISTINCT a) +2 +EXPLAIN SELECT COUNT(DISTINCT a, b + 0) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL a 10 NULL 16 Using index +SELECT COUNT(DISTINCT a, b + 0) FROM t1; +COUNT(DISTINCT a, b + 0) +16 +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10; +COUNT(DISTINCT a) +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 16 +SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10; +COUNT(DISTINCT a) +2 +EXPLAIN SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by +SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10; +1 +1 +EXPLAIN SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by +SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1; +1 +1 +1 +EXPLAIN SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1_1 index NULL a 10 NULL 16 Using index; Using temporary; Using filesort +1 SIMPLE t1_2 index NULL a 10 NULL 16 Using index; Using join buffer +SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a; +COUNT(DISTINCT t1_1.a) +1 +1 +EXPLAIN SELECT COUNT(DISTINCT a), 12 FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT a), 12 FROM t1; +COUNT(DISTINCT a) 12 +2 12 +EXPLAIN SELECT COUNT(DISTINCT a, b, c) FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT a, b, c) FROM t2; +COUNT(DISTINCT a, b, c) +16 +EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2; +COUNT(DISTINCT a) SUM(DISTINCT a) AVG(DISTINCT a) +2 3 1.5000 +EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 16 +SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2; +COUNT(DISTINCT a) SUM(DISTINCT a) AVG(DISTINCT f) +2 3 1.0000 +EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2; +COUNT(DISTINCT a, b) COUNT(DISTINCT b, a) +16 16 +EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 16 +SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2; +COUNT(DISTINCT a, b) COUNT(DISTINCT b, f) +16 8 +EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 16 +SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2; +COUNT(DISTINCT a, b) COUNT(DISTINCT b, d) +16 8 +EXPLAIN SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by +SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c; +a c COUNT(DISTINCT c, a, b) +1 1 1 +1 1 1 +1 1 1 +1 1 1 +1 1 1 +1 1 1 +1 1 1 +2 1 1 +2 1 1 +2 1 1 +2 1 1 +2 1 1 +2 1 1 +2 1 1 +2 1 1 +2 1 1 +EXPLAIN SELECT COUNT(DISTINCT c, a, b) FROM t2 +WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 15 NULL 1 Using where; Using index for group-by +SELECT COUNT(DISTINCT c, a, b) FROM t2 +WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c; +COUNT(DISTINCT c, a, b) +EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5 +GROUP BY b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref a a 5 const 1 Using where; Using index +SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5 +GROUP BY b; +COUNT(DISTINCT b) SUM(DISTINCT b) +EXPLAIN SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by +SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a; +a COUNT(DISTINCT b) SUM(DISTINCT b) +2 8 36 +2 8 36 +EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by +SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a; +COUNT(DISTINCT b) SUM(DISTINCT b) +8 36 +8 36 +EXPLAIN SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 16 Using where +SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42; +COUNT(DISTINCT a, b) +0 +EXPLAIN SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2 +WHERE b = 13 AND c = 42 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 15 NULL 9 Using where; Using index for group-by +SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2 +WHERE b = 13 AND c = 42 GROUP BY a; +a COUNT(DISTINCT a) SUM(DISTINCT a) +EXPLAIN SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 10 NULL 9 Using where; Using index for group-by +SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42; +COUNT(DISTINCT a, b) SUM(DISTINCT a) +0 NULL +EXPLAIN SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by +SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a; +SUM(DISTINCT a) MAX(b) +1 8 +2 8 +EXPLAIN SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by +SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c; +42 * (a + c + COUNT(DISTINCT c, a, b)) +126 +126 +126 +126 +126 +126 +126 +168 +168 +168 +168 +168 +168 +168 +168 +168 +EXPLAIN SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by +SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a; +(SUM(DISTINCT a) + MAX(b)) +9 +10 +DROP TABLE t1,t2; +# end of WL#3220 tests diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index c09a4fbf490..3ff3b96d829 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -570,13 +570,13 @@ explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); explain extended select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a'); -explain extended select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); +explain extended select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a'); -select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); +select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a'); # # Queries with expressions in the select clause @@ -1033,3 +1033,124 @@ SELECT a, MAX(b) FROM t WHERE b GROUP BY a; DROP TABLE t; --echo End of 5.1 tests + + +--echo # +--echo # WL#3220 (Loose index scan for COUNT DISTINCT) +--echo # + +CREATE TABLE t1 (a INT, b INT, c INT, KEY (a,b)); +INSERT INTO t1 VALUES (1,1,1), (1,2,1), (1,3,1), (1,4,1); +INSERT INTO t1 SELECT a, b + 4, 1 FROM t1; +INSERT INTO t1 SELECT a + 1, b, 1 FROM t1; +CREATE TABLE t2 (a INT, b INT, c INT, d INT, e INT, f INT, KEY (a,b,c)); +INSERT INTO t2 VALUES (1,1,1,1,1,1), (1,2,1,1,1,1), (1,3,1,1,1,1), + (1,4,1,1,1,1); +INSERT INTO t2 SELECT a, b + 4, c,d,e,f FROM t2; +INSERT INTO t2 SELECT a + 1, b, c,d,e,f FROM t2; + +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1; +SELECT COUNT(DISTINCT a) FROM t1; + +EXPLAIN SELECT COUNT(DISTINCT a,b) FROM t1; +SELECT COUNT(DISTINCT a,b) FROM t1; + +EXPLAIN SELECT COUNT(DISTINCT b,a) FROM t1; +SELECT COUNT(DISTINCT b,a) FROM t1; + +EXPLAIN SELECT COUNT(DISTINCT b) FROM t1; +SELECT COUNT(DISTINCT b) FROM t1; + +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a; +SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a; + +EXPLAIN SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a; +SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a; + +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b; +SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b; + +EXPLAIN SELECT DISTINCT COUNT(DISTINCT a) FROM t1; +SELECT DISTINCT COUNT(DISTINCT a) FROM t1; + +EXPLAIN SELECT COUNT(DISTINCT a, b + 0) FROM t1; +SELECT COUNT(DISTINCT a, b + 0) FROM t1; + +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10; +SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10; + +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10; +SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10; + +EXPLAIN SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10; +SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10; + +EXPLAIN SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1; +SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1; + +EXPLAIN SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a; +SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a; + +EXPLAIN SELECT COUNT(DISTINCT a), 12 FROM t1; +SELECT COUNT(DISTINCT a), 12 FROM t1; + +EXPLAIN SELECT COUNT(DISTINCT a, b, c) FROM t2; +SELECT COUNT(DISTINCT a, b, c) FROM t2; + +EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2; +SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2; + +EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2; +SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2; + +EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2; +SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2; + +EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2; +SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2; + +EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2; +SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2; + +EXPLAIN SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c; +SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c; + +EXPLAIN SELECT COUNT(DISTINCT c, a, b) FROM t2 + WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c; +SELECT COUNT(DISTINCT c, a, b) FROM t2 + WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c; + +EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5 + GROUP BY b; +SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5 + GROUP BY b; + +EXPLAIN SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a; +SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a; + +EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a; +SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a; + +EXPLAIN SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42; +SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42; + +EXPLAIN SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2 + WHERE b = 13 AND c = 42 GROUP BY a; +SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2 + WHERE b = 13 AND c = 42 GROUP BY a; + +EXPLAIN SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42; +SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42; + +EXPLAIN SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a; +SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a; + +EXPLAIN SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c; +SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c; + +EXPLAIN SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a; +SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a; + +DROP TABLE t1,t2; + +--echo # end of WL#3220 tests diff --git a/sql/field.h b/sql/field.h index a9299256f88..ffcf665d45f 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1934,9 +1934,12 @@ public: virtual bool str_needs_quotes() { return TRUE; } my_decimal *val_decimal(my_decimal *); int cmp(const uchar *a, const uchar *b) - { - DBUG_ASSERT(ptr == a); - return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len)); + { + DBUG_ASSERT(ptr == a || ptr == b); + if (ptr == a) + return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len)); + else + return Field_bit::key_cmp(a, bytes_in_rec+test(bit_len)) * -1; } int cmp_binary_offset(uint row_offset) { return cmp_offset(row_offset); } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index ceb553f1c8a..c8576722c69 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -374,6 +374,7 @@ Item_sum::Item_sum(List &list) :arg_count(list.elements), args= NULL; } mark_as_sum_func(); + init_aggregator(); list.empty(); // Fields are used } @@ -405,6 +406,10 @@ Item_sum::Item_sum(THD *thd, Item_sum *item): } memcpy(args, item->args, sizeof(Item*)*arg_count); memcpy(orig_args, item->orig_args, sizeof(Item*)*arg_count); + init_aggregator(); + with_distinct= item->with_distinct; + if (item->aggr) + set_aggregator(item->aggr->Aggrtype()); } @@ -550,13 +555,513 @@ void Item_sum::update_used_tables () } -Item *Item_sum::set_arg(int i, THD *thd, Item *new_val) +Item *Item_sum::set_arg(uint i, THD *thd, Item *new_val) { thd->change_item_tree(args + i, new_val); return new_val; } +int Item_sum::set_aggregator(Aggregator::Aggregator_type aggregator) +{ + switch (aggregator) + { + case Aggregator::DISTINCT_AGGREGATOR: + aggr= new Aggregator_distinct(this); + break; + + case Aggregator::SIMPLE_AGGREGATOR: + aggr= new Aggregator_simple(this); + break; + }; + return aggr ? FALSE : TRUE; +} + + +void Item_sum::cleanup() +{ + if (aggr) + { + delete aggr; + aggr= NULL; + } + Item_result_field::cleanup(); + forced_const= FALSE; +} + + +/** + Compare keys consisting of single field that cannot be compared as binary. + + Used by the Unique class to compare keys. Will do correct comparisons + for all field types. + + @param arg Pointer to the relevant Field class instance + @param key1 left key image + @param key2 right key image + @return comparison result + @retval < 0 if key1 < key2 + @retval = 0 if key1 = key2 + @retval > 0 if key1 > key2 +*/ + +static int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2) +{ + Field *f= (Field*) arg; + return f->cmp(key1, key2); +} + + +/** + Correctly compare composite keys. + + Used by the Unique class to compare keys. Will do correct comparisons + for composite keys with various field types. + + @param arg Pointer to the relevant Aggregator_distinct instance + @param key1 left key image + @param key2 right key image + @return comparison result + @retval <0 if key1 < key2 + @retval =0 if key1 = key2 + @retval >0 if key1 > key2 +*/ + +int Aggregator_distinct::composite_key_cmp(void* arg, uchar* key1, uchar* key2) +{ + Aggregator_distinct *aggr= (Aggregator_distinct *) arg; + Field **field = aggr->table->field; + Field **field_end= field + aggr->table->s->fields; + uint32 *lengths=aggr->field_lengths; + for (; field < field_end; ++field) + { + Field* f = *field; + int len = *lengths++; + int res = f->cmp(key1, key2); + if (res) + return res; + key1 += len; + key2 += len; + } + return 0; +} + + +static enum enum_field_types +calc_tmp_field_type(enum enum_field_types table_field_type, + Item_result result_type) +{ + /* Adjust tmp table type according to the chosen aggregation type */ + switch (result_type) { + case STRING_RESULT: + case REAL_RESULT: + if (table_field_type != MYSQL_TYPE_FLOAT) + table_field_type= MYSQL_TYPE_DOUBLE; + break; + case INT_RESULT: + table_field_type= MYSQL_TYPE_LONGLONG; + /* fallthrough */ + case DECIMAL_RESULT: + if (table_field_type != MYSQL_TYPE_LONGLONG) + table_field_type= MYSQL_TYPE_NEWDECIMAL; + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + return table_field_type; +} + + +/***************************************************************************/ + +C_MODE_START + +/* Declarations for auxilary C-callbacks */ + +static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2) +{ + return memcmp(key1, key2, *(uint *) arg); +} + + +static int item_sum_distinct_walk(void *element, element_count num_of_dups, + void *item) +{ + return ((Aggregator_distinct*) (item))->unique_walk_function(element); +} + +C_MODE_END + +/***************************************************************************/ +/** + Called before feeding the first row. Used to allocate/setup + the internal structures used for aggregation. + + @param thd Thread descriptor + @return status + @retval FALSE success + @retval TRUE faliure + + Prepares Aggregator_distinct to process the incoming stream. + Creates the temporary table and the Unique class if needed. + Called by Item_sum::aggregator_setup() +*/ + +bool Aggregator_distinct::setup(THD *thd) +{ + endup_done= FALSE; + /* + Setup can be called twice for ROLLUP items. This is a bug. + Please add DBUG_ASSERT(tree == 0) here when it's fixed. + */ + if (tree || table || tmp_table_param) + return FALSE; + + if (item_sum->setup(thd)) + return TRUE; + if (item_sum->sum_func() == Item_sum::COUNT_FUNC || + item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC) + { + List list; + SELECT_LEX *select_lex= thd->lex->current_select; + + if (!(tmp_table_param= new TMP_TABLE_PARAM)) + return TRUE; + + /* Create a table with an unique key over all parameters */ + for (uint i=0; i < item_sum->get_arg_count() ; i++) + { + Item *item=item_sum->get_arg(i); + if (list.push_back(item)) + return TRUE; // End of memory + if (item->const_item() && item->is_null()) + always_null=1; + } + if (always_null) + return FALSE; + count_field_types(select_lex,tmp_table_param,list,0); + tmp_table_param->force_copy_fields= item_sum->force_copy_fields; + DBUG_ASSERT(table == 0); + /* + Make create_tmp_table() convert BIT columns to BIGINT. + This is needed because BIT fields store parts of their data in table's + null bits, and we don't have methods to compare two table records, which + is needed by Unique which is used when HEAP table is used. + */ + { + List_iterator_fast li(list); + Item *item; + while ((item= li++)) + { + if (item->type() == Item::FIELD_ITEM && + ((Item_field*)item)->field->type() == FIELD_TYPE_BIT) + item->marker=4; + } + } + if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, + 0, + (select_lex->options | thd->options), + HA_POS_ERROR, (char*)""))) + return TRUE; + table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows + table->no_rows=1; + + if (table->s->db_type() == heap_hton) + { + /* + No blobs, otherwise it would have been MyISAM: set up a compare + function and its arguments to use with Unique. + */ + qsort_cmp2 compare_key; + void* cmp_arg; + Field **field= table->field; + Field **field_end= field + table->s->fields; + bool all_binary= TRUE; + + for (tree_key_length= 0; field < field_end; ++field) + { + Field *f= *field; + enum enum_field_types type= f->type(); + tree_key_length+= f->pack_length(); + if ((type == MYSQL_TYPE_VARCHAR) || + (!f->binary() && (type == MYSQL_TYPE_STRING || + type == MYSQL_TYPE_VAR_STRING))) + { + all_binary= FALSE; + break; + } + } + if (all_binary) + { + cmp_arg= (void*) &tree_key_length; + compare_key= (qsort_cmp2) simple_raw_key_cmp; + } + else + { + if (table->s->fields == 1) + { + /* + If we have only one field, which is the most common use of + count(distinct), it is much faster to use a simpler key + compare method that can take advantage of not having to worry + about other fields. + */ + compare_key= (qsort_cmp2) simple_str_key_cmp; + cmp_arg= (void*) table->field[0]; + /* tree_key_length has been set already */ + } + else + { + uint32 *length; + compare_key= (qsort_cmp2) composite_key_cmp; + cmp_arg= (void*) this; + field_lengths= (uint32*) thd->alloc(table->s->fields * sizeof(uint32)); + for (tree_key_length= 0, length= field_lengths, field= table->field; + field < field_end; ++field, ++length) + { + *length= (*field)->pack_length(); + tree_key_length+= *length; + } + } + } + DBUG_ASSERT(tree == 0); + tree= new Unique(compare_key, cmp_arg, tree_key_length, + thd->variables.max_heap_table_size); + /* + The only time tree_key_length could be 0 is if someone does + count(distinct) on a char(0) field - stupid thing to do, + but this has to be handled - otherwise someone can crash + the server with a DoS attack + */ + if (! tree) + return TRUE; + } + return FALSE; + } + else + { + List field_list; + Create_field field_def; /* field definition */ + Item *arg; + DBUG_ENTER("Item_sum_distinct::setup"); + /* It's legal to call setup() more than once when in a subquery */ + if (tree) + return FALSE; + + /* + Virtual table and the tree are created anew on each re-execution of + PS/SP. Hence all further allocations are performed in the runtime + mem_root. + */ + if (field_list.push_back(&field_def)) + return TRUE; + + item_sum->null_value= item_sum->maybe_null= 1; + item_sum->quick_group= 0; + + DBUG_ASSERT(item_sum->get_arg(0)->fixed); + + arg = item_sum->get_arg(0); + if (arg->const_item()) + { + (void) arg->val_int(); + if (arg->null_value) + always_null=1; + } + + if (always_null) + return FALSE; + + enum enum_field_types field_type; + + field_type= calc_tmp_field_type(arg->field_type(), + arg->result_type()); + field_def.init_for_tmp_table(field_type, + arg->max_length, + arg->decimals, + arg->maybe_null, + arg->unsigned_flag); + + if (! (table= create_virtual_tmp_table(thd, field_list))) + return TRUE; + + /* XXX: check that the case of CHAR(0) works OK */ + tree_key_length= table->s->reclength - table->s->null_bytes; + + /* + Unique handles all unique elements in a tree until they can't fit + in. Then the tree is dumped to the temporary file. We can use + simple_raw_key_cmp because the table contains numbers only; decimals + are converted to binary representation as well. + */ + tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length, + thd->variables.max_heap_table_size); + + DBUG_RETURN(tree == 0); + } +} + + +/** + Invalidate calculated value and clear the distinct rows. + + Frees space used by the internal data structures. + Removes the accumulated distinct rows. Invalidates the calculated result. +*/ + +void Aggregator_distinct::clear() +{ + endup_done= FALSE; + item_sum->clear(); + if (tree) + tree->reset(); + /* tree and table can be both null only if always_null */ + if (item_sum->sum_func() == Item_sum::COUNT_FUNC || + item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC) + { + if (!tree && table) + { + table->file->extra(HA_EXTRA_NO_CACHE); + table->file->ha_delete_all_rows(); + table->file->extra(HA_EXTRA_WRITE_CACHE); + } + } + else + { + item_sum->null_value= 1; + } +} + + +/** + Process incoming row. + + Add it to Unique/temp hash table if it's unique. Skip the row if + not unique. + Prepare Aggregator_distinct to process the incoming stream. + Create the temporary table and the Unique class if needed. + Called by Item_sum::aggregator_add(). + To actually get the result value in item_sum's buffers + Aggregator_distinct::endup() must be called. + + @return status + @retval FALSE success + @retval TRUE failure +*/ + +bool Aggregator_distinct::add() +{ + if (always_null) + return 0; + + if (item_sum->sum_func() == Item_sum::COUNT_FUNC || + item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC) + { + int error; + copy_fields(tmp_table_param); + copy_funcs(tmp_table_param->items_to_copy); + + for (Field **field=table->field ; *field ; field++) + if ((*field)->is_real_null(0)) + return 0; // Don't count NULL + + if (tree) + { + /* + The first few bytes of record (at least one) are just markers + for deleted and NULLs. We want to skip them since they will + bloat the tree without providing any valuable info. Besides, + key_length used to initialize the tree didn't include space for them. + */ + return tree->unique_add(table->record[0] + table->s->null_bytes); + } + if ((error= table->file->ha_write_row(table->record[0])) && + table->file->is_fatal_error(error, HA_CHECK_DUP)) + return TRUE; + return FALSE; + } + else + { + item_sum->get_arg(0)->save_in_field(table->field[0], FALSE); + if (table->field[0]->is_null()) + return 0; + DBUG_ASSERT(tree); + item_sum->null_value= 0; + /* + '0' values are also stored in the tree. This doesn't matter + for SUM(DISTINCT), but is important for AVG(DISTINCT) + */ + return tree->unique_add(table->field[0]->ptr); + } +} + + +/** + Calculate the aggregate function value. + + Since Distinct_aggregator::add() just collects the distinct rows, + we must go over the distinct rows and feed them to the aggregation + function before returning its value. + This is what endup () does. It also sets the result validity flag + endup_done to TRUE so it will not recalculate the aggregate value + again if the Item_sum hasn't been reset. +*/ + +void Aggregator_distinct::endup() +{ + /* prevent consecutive recalculations */ + if (endup_done) + return; + + /* we are going to calculate the aggregate value afresh */ + item_sum->clear(); + + /* The result will definitely be null : no more calculations needed */ + if (always_null) + return; + + if (item_sum->sum_func() == Item_sum::COUNT_FUNC || + item_sum->sum_func() == Item_sum::COUNT_DISTINCT_FUNC) + { + DBUG_ASSERT(item_sum->fixed == 1); + Item_sum_count *sum= (Item_sum_count *)item_sum; + if (tree && tree->elements == 0) + { + /* everything fits in memory */ + sum->count= (longlong) tree->elements_in_tree(); + endup_done= TRUE; + } + if (!tree) + { + /* there were blobs */ + table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + sum->count= table->file->stats.records; + endup_done= TRUE; + } + } + else + { + /* + We don't have a tree only if 'setup()' hasn't been called; + this is the case of sql_select.cc:return_zero_rows. + */ + if (tree) + table->field[0]->set_notnull(); + } + + if (tree && !endup_done) + { + /* go over the tree of distinct keys and calculate the aggregate value */ + use_distinct_values= TRUE; + tree->walk(item_sum_distinct_walk, (void*) this); + use_distinct_values= FALSE; + } + /* prevent consecutive recalculations */ + endup_done= TRUE; +} + + String * Item_sum_num::val_str(String *str) { @@ -823,10 +1328,27 @@ void Item_sum_sum::fix_length_and_dec() bool Item_sum_sum::add() { DBUG_ENTER("Item_sum_sum::add"); + bool arg_is_null; if (hybrid_type == DECIMAL_RESULT) { - my_decimal value, *val= args[0]->val_decimal(&value); - if (!args[0]->null_value) + my_decimal value, *val; + if (aggr->use_distinct_values) + { + /* + We are aggregating distinct rows. Get the value from the distinct + table pointer + */ + Aggregator_distinct *daggr= (Aggregator_distinct *)aggr; + val= daggr->table->field[0]->val_decimal (&value); + arg_is_null= daggr->table->field[0]->is_null(); + } + else + { + /* non-distinct aggregation */ + val= args[0]->val_decimal(&value); + arg_is_null= args[0]->null_value; + } + if (!arg_is_null) { my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1), val, dec_buffs + curr_dec_buff); @@ -836,8 +1358,25 @@ bool Item_sum_sum::add() } else { - sum+= args[0]->val_real(); - if (!args[0]->null_value) + double val; + if (aggr->use_distinct_values) + { + /* + We are aggregating distinct rows. Get the value from the distinct + table pointer + */ + Aggregator_distinct *daggr= (Aggregator_distinct *)aggr; + val= daggr->table->field[0]->val_real (); + arg_is_null= daggr->table->field[0]->is_null(); + } + else + { + /* non-distinct aggregation */ + val= args[0]->val_real(); + arg_is_null= args[0]->null_value; + } + sum+= val; + if (!arg_is_null) null_value= 0; } DBUG_RETURN(0); @@ -847,6 +1386,8 @@ bool Item_sum_sum::add() longlong Item_sum_sum::val_int() { DBUG_ASSERT(fixed == 1); + if (aggr) + aggr->endup(); if (hybrid_type == DECIMAL_RESULT) { longlong result; @@ -861,6 +1402,8 @@ longlong Item_sum_sum::val_int() double Item_sum_sum::val_real() { DBUG_ASSERT(fixed == 1); + if (aggr) + aggr->endup(); if (hybrid_type == DECIMAL_RESULT) my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum); return sum; @@ -869,6 +1412,8 @@ double Item_sum_sum::val_real() String *Item_sum_sum::val_str(String *str) { + if (aggr) + aggr->endup(); if (hybrid_type == DECIMAL_RESULT) return val_string_from_decimal(str); return val_string_from_real(str); @@ -877,311 +1422,54 @@ String *Item_sum_sum::val_str(String *str) my_decimal *Item_sum_sum::val_decimal(my_decimal *val) { + if (aggr) + aggr->endup(); if (hybrid_type == DECIMAL_RESULT) return (dec_buffs + curr_dec_buff); return val_decimal_from_real(val); } -/***************************************************************************/ - -C_MODE_START - -/* Declarations for auxilary C-callbacks */ - -static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2) -{ - return memcmp(key1, key2, *(uint *) arg); -} - - -static int item_sum_distinct_walk(void *element, element_count num_of_dups, - void *item) -{ - return ((Item_sum_distinct*) (item))->unique_walk_function(element); -} - -C_MODE_END - -/* Item_sum_distinct */ - -Item_sum_distinct::Item_sum_distinct(Item *item_arg) - :Item_sum_num(item_arg), tree(0) -{ - /* - quick_group is an optimizer hint, which means that GROUP BY can be - handled with help of index on grouped columns. - By setting quick_group to zero we force creation of temporary table - to perform GROUP BY. - */ - quick_group= 0; -} - - -Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original) - :Item_sum_num(thd, original), val(original->val), tree(0), - table_field_type(original->table_field_type) -{ - quick_group= 0; -} - - /** - Behaves like an Integer except to fix_length_and_dec(). - Additionally div() converts val with this traits to a val with true - decimal traits along with conversion of integer value to decimal value. - This is to speedup SUM/AVG(DISTINCT) evaluation for 8-32 bit integer - values. + Aggregate a distinct row from the distinct hash table. + + Called for each row into the hash table 'Aggregator_distinct::table'. + Includes the current distinct row into the calculation of the + aggregate value. Uses the Field classes to get the value from the row. + This function is used for AVG/SUM(DISTINCT). For COUNT(DISTINCT) + it's called only when there are no blob arguments and the data don't + fit into memory (so Unique makes persisted trees on disk). + + @param element pointer to the row data. + + @return status + @retval FALSE success + @retval TRUE failure */ -struct Hybrid_type_traits_fast_decimal: public - Hybrid_type_traits_integer -{ - virtual Item_result type() const { return DECIMAL_RESULT; } - virtual void fix_length_and_dec(Item *item, Item *arg) const - { Hybrid_type_traits_decimal::instance()->fix_length_and_dec(item, arg); } - - virtual void div(Hybrid_type *val, ulonglong u) const - { - int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, val->dec_buf); - val->used_dec_buf_no= 0; - val->traits= Hybrid_type_traits_decimal::instance(); - val->traits->div(val, u); - } - static const Hybrid_type_traits_fast_decimal *instance(); - Hybrid_type_traits_fast_decimal() {}; -}; - -static const Hybrid_type_traits_fast_decimal fast_decimal_traits_instance; - -const Hybrid_type_traits_fast_decimal - *Hybrid_type_traits_fast_decimal::instance() -{ - return &fast_decimal_traits_instance; -} - -void Item_sum_distinct::fix_length_and_dec() -{ - DBUG_ASSERT(args[0]->fixed); - - table_field_type= args[0]->field_type(); - - /* Adjust tmp table type according to the chosen aggregation type */ - switch (args[0]->result_type()) { - case STRING_RESULT: - case REAL_RESULT: - val.traits= Hybrid_type_traits::instance(); - if (table_field_type != MYSQL_TYPE_FLOAT) - table_field_type= MYSQL_TYPE_DOUBLE; - break; - case INT_RESULT: - /* - Preserving int8, int16, int32 field types gives ~10% performance boost - as the size of result tree becomes significantly smaller. - Another speed up we gain by using longlong for intermediate - calculations. The range of int64 is enough to hold sum 2^32 distinct - integers each <= 2^32. - */ - if (table_field_type == MYSQL_TYPE_INT24 || - (table_field_type >= MYSQL_TYPE_TINY && - table_field_type <= MYSQL_TYPE_LONG)) - { - val.traits= Hybrid_type_traits_fast_decimal::instance(); - break; - } - table_field_type= MYSQL_TYPE_LONGLONG; - /* fallthrough */ - case DECIMAL_RESULT: - val.traits= Hybrid_type_traits_decimal::instance(); - if (table_field_type != MYSQL_TYPE_LONGLONG) - table_field_type= MYSQL_TYPE_NEWDECIMAL; - break; - case ROW_RESULT: - default: - DBUG_ASSERT(0); - } - val.traits->fix_length_and_dec(this, args[0]); -} - - -/** - @todo - check that the case of CHAR(0) works OK -*/ -bool Item_sum_distinct::setup(THD *thd) -{ - List field_list; - Create_field field_def; /* field definition */ - DBUG_ENTER("Item_sum_distinct::setup"); - /* It's legal to call setup() more than once when in a subquery */ - if (tree) - DBUG_RETURN(FALSE); - - /* - Virtual table and the tree are created anew on each re-execution of - PS/SP. Hence all further allocations are performed in the runtime - mem_root. - */ - if (field_list.push_back(&field_def)) - DBUG_RETURN(TRUE); - - null_value= maybe_null= 1; - quick_group= 0; - - DBUG_ASSERT(args[0]->fixed); - - field_def.init_for_tmp_table(table_field_type, args[0]->max_length, - args[0]->decimals, args[0]->maybe_null, - args[0]->unsigned_flag); - - if (! (table= create_virtual_tmp_table(thd, field_list))) - DBUG_RETURN(TRUE); - - /* XXX: check that the case of CHAR(0) works OK */ - tree_key_length= table->s->reclength - table->s->null_bytes; - - /* - Unique handles all unique elements in a tree until they can't fit - in. Then the tree is dumped to the temporary file. We can use - simple_raw_key_cmp because the table contains numbers only; decimals - are converted to binary representation as well. - */ - tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length, - thd->variables.max_heap_table_size); - - is_evaluated= FALSE; - DBUG_RETURN(tree == 0); -} - - -bool Item_sum_distinct::add() -{ - args[0]->save_in_field(table->field[0], FALSE); - is_evaluated= FALSE; - if (!table->field[0]->is_null()) - { - DBUG_ASSERT(tree); - null_value= 0; - /* - '0' values are also stored in the tree. This doesn't matter - for SUM(DISTINCT), but is important for AVG(DISTINCT) - */ - return tree->unique_add(table->field[0]->ptr); - } - return 0; -} - - -bool Item_sum_distinct::unique_walk_function(void *element) + +bool Aggregator_distinct::unique_walk_function(void *element) { memcpy(table->field[0]->ptr, element, tree_key_length); - ++count; - val.traits->add(&val, table->field[0]); + item_sum->add(); return 0; } -void Item_sum_distinct::clear() +Aggregator_distinct::~Aggregator_distinct() { - DBUG_ENTER("Item_sum_distinct::clear"); - DBUG_ASSERT(tree != 0); /* we always have a tree */ - null_value= 1; - tree->reset(); - is_evaluated= FALSE; - DBUG_VOID_RETURN; -} - -void Item_sum_distinct::cleanup() -{ - Item_sum_num::cleanup(); - delete tree; - tree= 0; - table= 0; - is_evaluated= FALSE; -} - -Item_sum_distinct::~Item_sum_distinct() -{ - delete tree; - /* no need to free the table */ -} - - -void Item_sum_distinct::calculate_val_and_count() -{ - if (!is_evaluated) + if (tree) { - count= 0; - val.traits->set_zero(&val); - /* - We don't have a tree only if 'setup()' hasn't been called; - this is the case of sql_select.cc:return_zero_rows. - */ - if (tree) - { - table->field[0]->set_notnull(); - tree->walk(item_sum_distinct_walk, (void*) this); - } - is_evaluated= TRUE; + delete tree; + tree= NULL; } -} - - -double Item_sum_distinct::val_real() -{ - calculate_val_and_count(); - return val.traits->val_real(&val); -} - - -my_decimal *Item_sum_distinct::val_decimal(my_decimal *to) -{ - calculate_val_and_count(); - if (null_value) - return 0; - return val.traits->val_decimal(&val, to); -} - - -longlong Item_sum_distinct::val_int() -{ - calculate_val_and_count(); - return val.traits->val_int(&val, unsigned_flag); -} - - -String *Item_sum_distinct::val_str(String *str) -{ - calculate_val_and_count(); - if (null_value) - return 0; - return val.traits->val_str(&val, str, decimals); -} - -/* end of Item_sum_distinct */ - -/* Item_sum_avg_distinct */ - -void -Item_sum_avg_distinct::fix_length_and_dec() -{ - Item_sum_distinct::fix_length_and_dec(); - prec_increment= current_thd->variables.div_precincrement; - /* - AVG() will divide val by count. We need to reserve digits - after decimal point as the result can be fractional. - */ - decimals= min(decimals + prec_increment, NOT_FIXED_DEC); -} - - -void -Item_sum_avg_distinct::calculate_val_and_count() -{ - if (!is_evaluated) + if (table) { - Item_sum_distinct::calculate_val_and_count(); - if (count) - val.traits->div(&val, count); - is_evaluated= TRUE; + free_tmp_table(table->in_use, table); + table=NULL; + } + if (tmp_table_param) + { + delete tmp_table_param; + tmp_table_param= NULL; } } @@ -1208,6 +1496,8 @@ bool Item_sum_count::add() longlong Item_sum_count::val_int() { DBUG_ASSERT(fixed == 1); + if (aggr) + aggr->endup(); return (longlong) count; } @@ -1298,6 +1588,8 @@ bool Item_sum_avg::add() double Item_sum_avg::val_real() { DBUG_ASSERT(fixed == 1); + if (aggr) + aggr->endup(); if (!count) { null_value=1; @@ -1312,6 +1604,8 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val) my_decimal sum_buff, cnt; const my_decimal *sum_dec; DBUG_ASSERT(fixed == 1); + if (aggr) + aggr->endup(); if (!count) { null_value=1; @@ -1334,6 +1628,8 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val) String *Item_sum_avg::val_str(String *str) { + if (aggr) + aggr->endup(); if (hybrid_type == DECIMAL_RESULT) return val_string_from_decimal(str); return val_string_from_real(str); @@ -2029,6 +2325,7 @@ void Item_sum_hybrid::reset_field() void Item_sum_sum::reset_field() { + DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); if (hybrid_type == DECIMAL_RESULT) { my_decimal value, *arg_val= args[0]->val_decimal(&value); @@ -2053,6 +2350,7 @@ void Item_sum_count::reset_field() { uchar *res=result_field->ptr; longlong nr=0; + DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); if (!args[0]->maybe_null || !args[0]->is_null()) nr=1; @@ -2063,6 +2361,7 @@ void Item_sum_count::reset_field() void Item_sum_avg::reset_field() { uchar *res=result_field->ptr; + DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); if (hybrid_type == DECIMAL_RESULT) { longlong tmp; @@ -2116,6 +2415,7 @@ void Item_sum_bit::update_field() void Item_sum_sum::update_field() { + DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); if (hybrid_type == DECIMAL_RESULT) { my_decimal value, *arg_val= args[0]->val_decimal(&value); @@ -2168,6 +2468,9 @@ void Item_sum_avg::update_field() { longlong field_count; uchar *res=result_field->ptr; + + DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR); + if (hybrid_type == DECIMAL_RESULT) { my_decimal value, *arg_val= args[0]->val_decimal(&value); @@ -2469,318 +2772,6 @@ double Item_variance_field::val_real() } -/**************************************************************************** -** COUNT(DISTINCT ...) -****************************************************************************/ - -int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2) -{ - Field *f= (Field*) arg; - return f->cmp(key1, key2); -} - -/** - Did not make this one static - at least gcc gets confused when - I try to declare a static function as a friend. If you can figure - out the syntax to make a static function a friend, make this one - static -*/ - -int composite_key_cmp(void* arg, uchar* key1, uchar* key2) -{ - Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg; - Field **field = item->table->field; - Field **field_end= field + item->table->s->fields; - uint32 *lengths=item->field_lengths; - for (; field < field_end; ++field) - { - Field* f = *field; - int len = *lengths++; - int res = f->cmp(key1, key2); - if (res) - return res; - key1 += len; - key2 += len; - } - return 0; -} - - -C_MODE_START - -static int count_distinct_walk(void *elem, element_count count, void *arg) -{ - (*((ulonglong*)arg))++; - return 0; -} - -C_MODE_END - - -void Item_sum_count_distinct::cleanup() -{ - DBUG_ENTER("Item_sum_count_distinct::cleanup"); - Item_sum_int::cleanup(); - - /* Free objects only if we own them. */ - if (!original) - { - /* - We need to delete the table and the tree in cleanup() as - they were allocated in the runtime memroot. Using the runtime - memroot reduces memory footprint for PS/SP and simplifies setup(). - */ - delete tree; - tree= 0; - is_evaluated= FALSE; - if (table) - { - free_tmp_table(table->in_use, table); - table= 0; - } - delete tmp_table_param; - tmp_table_param= 0; - } - always_null= FALSE; - DBUG_VOID_RETURN; -} - - -/** - This is used by rollup to create a separate usable copy of - the function. -*/ - -void Item_sum_count_distinct::make_unique() -{ - table=0; - original= 0; - force_copy_fields= 1; - tree= 0; - is_evaluated= FALSE; - tmp_table_param= 0; - always_null= FALSE; -} - - -Item_sum_count_distinct::~Item_sum_count_distinct() -{ - cleanup(); -} - - -bool Item_sum_count_distinct::setup(THD *thd) -{ - List list; - SELECT_LEX *select_lex= thd->lex->current_select; - - /* - Setup can be called twice for ROLLUP items. This is a bug. - Please add DBUG_ASSERT(tree == 0) here when it's fixed. - It's legal to call setup() more than once when in a subquery - */ - if (tree || table || tmp_table_param) - return FALSE; - - if (!(tmp_table_param= new TMP_TABLE_PARAM)) - return TRUE; - - /* Create a table with an unique key over all parameters */ - for (uint i=0; i < arg_count ; i++) - { - Item *item=args[i]; - if (list.push_back(item)) - return TRUE; // End of memory - if (item->const_item() && item->is_null()) - always_null= 1; - } - if (always_null) - return FALSE; - count_field_types(select_lex, tmp_table_param, list, 0); - tmp_table_param->force_copy_fields= force_copy_fields; - DBUG_ASSERT(table == 0); - /* - Make create_tmp_table() convert BIT columns to BIGINT. - This is needed because BIT fields store parts of their data in table's - null bits, and we don't have methods to compare two table records, which - is needed by Unique which is used when HEAP table is used. - */ - { - List_iterator_fast li(list); - Item *item; - while ((item= li++)) - { - if (item->type() == Item::FIELD_ITEM && - ((Item_field*)item)->field->type() == FIELD_TYPE_BIT) - item->marker=4; - } - } - - if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, - 0, - (select_lex->options | thd->options), - HA_POS_ERROR, (char*)""))) - return TRUE; - table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows - table->no_rows=1; - - if (table->s->db_type() == heap_hton) - { - /* - No blobs, otherwise it would have been MyISAM: set up a compare - function and its arguments to use with Unique. - */ - qsort_cmp2 compare_key; - void* cmp_arg; - Field **field= table->field; - Field **field_end= field + table->s->fields; - bool all_binary= TRUE; - - for (tree_key_length= 0; field < field_end; ++field) - { - Field *f= *field; - enum enum_field_types f_type= f->type(); - tree_key_length+= f->pack_length(); - if ((f_type == MYSQL_TYPE_VARCHAR) || - (!f->binary() && (f_type == MYSQL_TYPE_STRING || - f_type == MYSQL_TYPE_VAR_STRING))) - { - all_binary= FALSE; - break; - } - } - if (all_binary) - { - cmp_arg= (void*) &tree_key_length; - compare_key= (qsort_cmp2) simple_raw_key_cmp; - } - else - { - if (table->s->fields == 1) - { - /* - If we have only one field, which is the most common use of - count(distinct), it is much faster to use a simpler key - compare method that can take advantage of not having to worry - about other fields. - */ - compare_key= (qsort_cmp2) simple_str_key_cmp; - cmp_arg= (void*) table->field[0]; - /* tree_key_length has been set already */ - } - else - { - uint32 *length; - compare_key= (qsort_cmp2) composite_key_cmp; - cmp_arg= (void*) this; - field_lengths= (uint32*) thd->alloc(table->s->fields * sizeof(uint32)); - for (tree_key_length= 0, length= field_lengths, field= table->field; - field < field_end; ++field, ++length) - { - *length= (*field)->pack_length(); - tree_key_length+= *length; - } - } - } - DBUG_ASSERT(tree == 0); - tree= new Unique(compare_key, cmp_arg, tree_key_length, - thd->variables.max_heap_table_size); - /* - The only time tree_key_length could be 0 is if someone does - count(distinct) on a char(0) field - stupid thing to do, - but this has to be handled - otherwise someone can crash - the server with a DoS attack - */ - is_evaluated= FALSE; - if (! tree) - return TRUE; - } - return FALSE; -} - - -Item *Item_sum_count_distinct::copy_or_same(THD* thd) -{ - return new (thd->mem_root) Item_sum_count_distinct(thd, this); -} - - -void Item_sum_count_distinct::clear() -{ - /* tree and table can be both null only if always_null */ - is_evaluated= FALSE; - if (tree) - { - tree->reset(); - } - else if (table) - { - table->file->extra(HA_EXTRA_NO_CACHE); - table->file->ha_delete_all_rows(); - table->file->extra(HA_EXTRA_WRITE_CACHE); - } -} - -bool Item_sum_count_distinct::add() -{ - int error; - if (always_null) - return 0; - copy_fields(tmp_table_param); - copy_funcs(tmp_table_param->items_to_copy); - - for (Field **field=table->field ; *field ; field++) - if ((*field)->is_real_null(0)) - return 0; // Don't count NULL - - is_evaluated= FALSE; - if (tree) - { - /* - The first few bytes of record (at least one) are just markers - for deleted and NULLs. We want to skip them since they will - bloat the tree without providing any valuable info. Besides, - key_length used to initialize the tree didn't include space for them. - */ - return tree->unique_add(table->record[0] + table->s->null_bytes); - } - if ((error= table->file->ha_write_row(table->record[0])) && - table->file->is_fatal_error(error, HA_CHECK_DUP)) - return TRUE; - return FALSE; -} - - -longlong Item_sum_count_distinct::val_int() -{ - int error; - DBUG_ASSERT(fixed == 1); - if (!table) // Empty query - return LL(0); - if (tree) - { - if (is_evaluated) - return count; - - if (tree->elements == 0) - return (longlong) tree->elements_in_tree(); // everything fits in memory - count= 0; - tree->walk(count_distinct_walk, (void*) &count); - is_evaluated= TRUE; - return (longlong) count; - } - - error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); - - if(error) - { - table->file->print_error(error, MYF(0)); - } - - return table->file->stats.records; -} - - /**************************************************************************** ** Functions to handle dynamic loadable aggregates ** Original source by: Alexis Mikhailov diff --git a/sql/item_sum.h b/sql/item_sum.h index 8a20e2dd165..1dd1c5b5dd5 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -22,7 +22,87 @@ #include -/* +class Item_sum; +class Aggregator_distinct; +class Aggregator_simple; + +/** + The abstract base class for the Aggregator_* classes. + It implements the data collection functions (setup/add/clear) + as either pass-through to the real functionality or + as collectors into an Unique (for distinct) structure. + + Note that update_field/reset_field are not in that + class, because they're simply not called when + GROUP BY/DISTINCT can be handled with help of index on grouped + fields (quick_group = 0); +*/ + +class Aggregator : public Sql_alloc +{ + friend class Item_sum; + friend class Item_sum_sum; + friend class Item_sum_count; + friend class Item_sum_avg; + + /* + All members are protected as this class is not usable outside of an + Item_sum descendant. + */ +protected: + /* the aggregate function class to act on */ + Item_sum *item_sum; + + /** + When feeding back the data in endup() from Unique/temp table back to + Item_sum::add() methods we must read the data from Unique (and not + recalculate the functions that are given as arguments to the aggregate + function. + This flag is to tell the add() methods to take the data from the Unique + instead by calling the relevant val_..() method + */ + + bool use_distinct_values; + +public: + Aggregator (Item_sum *arg): item_sum(arg), use_distinct_values(FALSE) {} + virtual ~Aggregator () {} /* Keep gcc happy */ + + enum Aggregator_type { SIMPLE_AGGREGATOR, DISTINCT_AGGREGATOR }; + virtual Aggregator_type Aggrtype() = 0; + + /** + Called before adding the first row. + Allocates and sets up the internal aggregation structures used, + e.g. the Unique instance used to calculate distinct. + */ + virtual bool setup(THD *) = 0; + + /** + Called when we need to wipe out all the data from the aggregator : + all the values acumulated and all the state. + Cleans up the internal structures and resets them to their initial state. + */ + virtual void clear() = 0; + + /** + Called when there's a new value to be aggregated. + Updates the internal state of the aggregator to reflect the new value. + */ + virtual bool add() = 0; + + /** + Called when there are no more data and the final value is to be retrieved. + Finalises the state of the aggregator, so the final result can be retrieved. + */ + virtual void endup() = 0; + +}; + + +class st_select_lex; + +/** Class Item_sum is the base class used for special expressions that SQL calls 'set functions'. These expressions are formed with the help of aggregate functions such as SUM, MAX, GROUP_CONCAT etc. @@ -215,13 +295,32 @@ TODO: to catch queries where the limit is exceeded to make the code clean here. -*/ - -class st_select_lex; +*/ class Item_sum :public Item_result_field { public: + /** + Aggregator class instance. Not set initially. Allocated only after + it is determined if the incoming data are already distinct. + */ + Aggregator *aggr; + + /** + Used in making ROLLUP. Set for the ROLLUP copies of the original + Item_sum and passed to create_tmp_field() to cause it to work + over the temp table buffer that is referenced by + Item_result_field::result_field. + */ + bool force_copy_fields; + + /** + Indicates how the aggregate function was specified by the parser : + 1 if it was written as AGGREGATE(DISTINCT), + 0 if it was AGGREGATE() + */ + bool with_distinct; + enum Sumfunctype { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC, AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC, @@ -263,47 +362,28 @@ public: Item_sum() :quick_group(1), arg_count(0), forced_const(FALSE) { mark_as_sum_func(); + init_aggregator(); } Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args), orig_args(tmp_orig_args), forced_const(FALSE) { args[0]=a; mark_as_sum_func(); + init_aggregator(); } Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args), orig_args(tmp_orig_args), forced_const(FALSE) { args[0]=a; args[1]=b; mark_as_sum_func(); + init_aggregator(); } Item_sum(List &list); //Copy constructor, need to perform subselects with temporary tables Item_sum(THD *thd, Item_sum *item); enum Type type() const { return SUM_FUNC_ITEM; } virtual enum Sumfunctype sum_func () const=0; - - /* - This method is similar to add(), but it is called when the current - aggregation group changes. Thus it performs a combination of - clear() and add(). - */ - inline bool reset() { clear(); return add(); }; - - /* - Prepare this item for evaluation of an aggregate value. This is - called by reset() when a group changes, or, for correlated - subqueries, between subquery executions. E.g. for COUNT(), this - method should set count= 0; - */ - virtual void clear()= 0; - - /* - This method is called for the next row in the same group. Its - purpose is to aggregate the new value to the previous values in - the group (i.e. since clear() was called last time). For example, - for COUNT(), do count++. - */ - virtual bool add()=0; + inline bool reset() { aggregator_clear(); return aggregator_add(); }; /* Called when new group is started and results are being saved in @@ -343,11 +423,6 @@ public: { return new Item_field(field); } table_map used_tables() const { return used_tables_cache; } void update_used_tables (); - void cleanup() - { - Item::cleanup(); - forced_const= FALSE; - } bool is_null() { return null_value; } void make_const () { @@ -359,7 +434,9 @@ public: virtual void print(String *str, enum_query_type query_type); void fix_num_length_and_dec(); - /* + /** + Mark an aggregate as having no rows. + This function is called by the execution engine to assign 'NO ROWS FOUND' value to an aggregate item, when the underlying result set has no rows. Such value, in a general case, may be different from @@ -367,10 +444,15 @@ public: may be initialized to 0 by clear() and to NULL by no_rows_in_result(). */ - void no_rows_in_result() { clear(); } - - virtual bool setup(THD *thd) {return 0;} - virtual void make_unique() {} + void no_rows_in_result() + { + if (!aggr) + set_aggregator(with_distinct ? + Aggregator::DISTINCT_AGGREGATOR : + Aggregator::SIMPLE_AGGREGATOR); + reset(); + } + virtual void make_unique() { force_copy_fields= TRUE; } Item *get_tmp_table_item(THD *thd); virtual Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); @@ -381,14 +463,178 @@ public: st_select_lex *depended_from() { return (nest_level == aggr_level ? 0 : aggr_sel); } - Item *get_arg(int i) { return args[i]; } - Item *set_arg(int i, THD *thd, Item *new_val); + Item *get_arg(uint i) { return args[i]; } + Item *set_arg(uint i, THD *thd, Item *new_val); uint get_arg_count() { return arg_count; } + + /* Initialization of distinct related members */ + void init_aggregator() + { + aggr= NULL; + with_distinct= FALSE; + force_copy_fields= FALSE; + } + + /** + Called to initialize the aggregator. + */ + + inline bool aggregator_setup(THD *thd) { return aggr->setup(thd); }; + + /** + Called to cleanup the aggregator. + */ + + inline void aggregator_clear() { aggr->clear(); } + + /** + Called to add value to the aggregator. + */ + + inline bool aggregator_add() { return aggr->add(); }; + + /* stores the declared DISTINCT flag (from the parser) */ + void set_distinct(bool distinct) + { + with_distinct= distinct; + quick_group= with_distinct ? 0 : 1; + } + + /** + Set the type of aggregation : DISTINCT or not. + + Called when the final determination is done about the aggregation + type and the object is about to be used. + */ + + int set_aggregator(Aggregator::Aggregator_type aggregator); + virtual void clear()= 0; + virtual bool add()= 0; + virtual bool setup(THD *thd) {return 0;} + + void cleanup (); +}; + + +class Unique; + + +/** + The distinct aggregator. + Implements AGGFN (DISTINCT ..) + Collects all the data into an Unique (similarly to what Item_sum_distinct + does currently) and then (if applicable) iterates over the list of + unique values and pumps them back into its object +*/ + +class Aggregator_distinct : public Aggregator +{ + friend class Item_sum_sum; + friend class Item_sum_count; + friend class Item_sum_avg; +protected: + + /* + flag to prevent consecutive runs of endup(). Normally in endup there are + expensive calculations (like walking the distinct tree for example) + which we must do only once if there are no data changes. + We can re-use the data for the second and subsequent val_xxx() calls. + endup_done set to TRUE also means that the calculated values for + the aggregate functions are correct and don't need recalculation. + */ + bool endup_done; + + /* + Used depending on the type of the aggregate function and the presence of + blob columns in it: + - For COUNT(DISTINCT) and no blob fields this points to a real temporary + table. It's used as a hash table. + - For AVG/SUM(DISTINCT) or COUNT(DISTINCT) with blob fields only the + in-memory data structure of a temporary table is constructed. + It's used by the Field classes to transform data into row format. + */ + TABLE *table; + + /* + An array of field lengths on row allocated and used only for + COUNT(DISTINCT) with multiple columns and no blobs. Used in + Aggregator_distinct::composite_key_cmp (called from Unique to compare + nodes + */ + uint32 *field_lengths; + + /* + used in conjunction with 'table' to support the access to Field classes + for COUNT(DISTINCT). Needed by copy_fields()/copy_funcs(). + */ + TMP_TABLE_PARAM *tmp_table_param; + + /* + If there are no blobs in the COUNT(DISTINCT) arguments, we can use a tree, + which is faster than heap table. In that case, we still use the table + to help get things set up, but we insert nothing in it. + For AVG/SUM(DISTINCT) we always use this tree (as it takes a single + argument) to get the distinct rows. + */ + Unique *tree; + + /* + The length of the temp table row. Must be a member of the class as it + gets passed down to simple_raw_key_cmp () as a compare function argument + to Unique. simple_raw_key_cmp () is used as a fast comparison function + when the entire row can be binary compared. + */ + uint tree_key_length; + + /* + Set to true if the result is known to be always NULL. + If set deactivates creation and usage of the temporary table (in the + 'table' member) and the Unique instance (in the 'tree' member) as well as + the calculation of the final value on the first call to + Item_[sum|avg|count]::val_xxx(). + */ + bool always_null; + +public: + Aggregator_distinct (Item_sum *sum) : + Aggregator(sum), table(NULL), tmp_table_param(NULL), tree(NULL), + always_null(FALSE) {} + virtual ~Aggregator_distinct (); + Aggregator_type Aggrtype() { return DISTINCT_AGGREGATOR; } + + bool setup(THD *); + void clear(); + bool add(); + void endup(); + + bool unique_walk_function(void *element); + static int composite_key_cmp(void* arg, uchar* key1, uchar* key2); +}; + + +/** + The pass-through aggregator. + Implements AGGFN (DISTINCT ..) by knowing it gets distinct data on input. + So it just pumps them back to the Item_sum descendant class. +*/ +class Aggregator_simple : public Aggregator +{ +public: + + Aggregator_simple (Item_sum *sum) : + Aggregator(sum) {} + Aggregator_type Aggrtype() { return Aggregator::SIMPLE_AGGREGATOR; } + + bool setup(THD * thd) { return item_sum->setup(thd); } + void clear() { item_sum->clear(); } + bool add() { return item_sum->add(); } + void endup() {}; }; class Item_sum_num :public Item_sum { + friend class Aggregator_distinct; protected: /* val_xxx() functions may be called several times during the execution of a @@ -443,9 +689,15 @@ protected: void fix_length_and_dec(); public: - Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {} + Item_sum_sum(Item *item_par, bool distinct= FALSE) :Item_sum_num(item_par) + { + set_distinct(distinct); + } Item_sum_sum(THD *thd, Item_sum_sum *item); - enum Sumfunctype sum_func () const {return SUM_FUNC;} + enum Sumfunctype sum_func () const + { + return with_distinct ? SUM_DISTINCT_FUNC : SUM_FUNC; + } void clear(); bool add(); double val_real(); @@ -456,109 +708,50 @@ public: void reset_field(); void update_field(); void no_rows_in_result() {} - const char *func_name() const { return "sum("; } + const char *func_name() const + { + return with_distinct ? "sum(distinct " : "sum("; + } Item *copy_or_same(THD* thd); }; - -/* Common class for SUM(DISTINCT), AVG(DISTINCT) */ - -class Unique; - -class Item_sum_distinct :public Item_sum_num -{ -protected: - /* storage for the summation result */ - ulonglong count; - Hybrid_type val; - /* storage for unique elements */ - Unique *tree; - TABLE *table; - enum enum_field_types table_field_type; - uint tree_key_length; -protected: - Item_sum_distinct(THD *thd, Item_sum_distinct *item); -public: - Item_sum_distinct(Item *item_par); - ~Item_sum_distinct(); - - bool setup(THD *thd); - void clear(); - void cleanup(); - bool add(); - double val_real(); - my_decimal *val_decimal(my_decimal *); - longlong val_int(); - String *val_str(String *str); - - /* XXX: does it need make_unique? */ - - enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } - void reset_field() {} // not used - void update_field() {} // not used - virtual void no_rows_in_result() {} - void fix_length_and_dec(); - enum Item_result result_type () const { return val.traits->type(); } - virtual void calculate_val_and_count(); - virtual bool unique_walk_function(void *elem); -}; - - -/* - Item_sum_sum_distinct - implementation of SUM(DISTINCT expr). - See also: MySQL manual, chapter 'Adding New Functions To MySQL' - and comments in item_sum.cc. -*/ - -class Item_sum_sum_distinct :public Item_sum_distinct -{ -private: - Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item) - :Item_sum_distinct(thd, item) {} -public: - Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {} - - enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } - const char *func_name() const { return "sum(distinct "; } - Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); } -}; - - -/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */ - -class Item_sum_avg_distinct: public Item_sum_distinct -{ -private: - Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original) - :Item_sum_distinct(thd, original) {} -public: - uint prec_increment; - Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {} - - void fix_length_and_dec(); - virtual void calculate_val_and_count(); - enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; } - const char *func_name() const { return "avg(distinct "; } - Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); } -}; - - class Item_sum_count :public Item_sum_int { longlong count; + friend class Aggregator_distinct; + + void clear(); + bool add(); + void cleanup(); + public: Item_sum_count(Item *item_par) :Item_sum_int(item_par),count(0) {} + + /** + Constructs an instance for COUNT(DISTINCT) + + @param list a list of the arguments to the aggregate function + + This constructor is called by the parser only for COUNT (DISTINCT). + */ + + Item_sum_count(List &list) + :Item_sum_int(list),count(0) + { + set_distinct(TRUE); + } Item_sum_count(THD *thd, Item_sum_count *item) :Item_sum_int(thd, item), count(item->count) {} - enum Sumfunctype sum_func () const { return COUNT_FUNC; } - void clear(); + enum Sumfunctype sum_func () const + { + return with_distinct ? COUNT_DISTINCT_FUNC : COUNT_FUNC; + } void no_rows_in_result() { count=0; } - bool add(); void make_const(longlong count_arg) { count=count_arg; @@ -566,79 +759,15 @@ class Item_sum_count :public Item_sum_int } longlong val_int(); void reset_field(); - void cleanup(); void update_field(); - const char *func_name() const { return "count("; } + const char *func_name() const + { + return with_distinct ? "count(distinct " : "count("; + } Item *copy_or_same(THD* thd); }; -class TMP_TABLE_PARAM; - -class Item_sum_count_distinct :public Item_sum_int -{ - TABLE *table; - uint32 *field_lengths; - TMP_TABLE_PARAM *tmp_table_param; - bool force_copy_fields; - /* - If there are no blobs, we can use a tree, which - is faster than heap table. In that case, we still use the table - to help get things set up, but we insert nothing in it - */ - Unique *tree; - /* - Storage for the value of count between calls to val_int() so val_int() - will not recalculate on each call. Validitiy of the value is stored in - is_evaluated. - */ - longlong count; - /* - Following is 0 normal object and pointer to original one for copy - (to correctly free resources) - */ - Item_sum_count_distinct *original; - uint tree_key_length; - - - bool always_null; // Set to 1 if the result is always NULL - - - friend int composite_key_cmp(void* arg, uchar* key1, uchar* key2); - friend int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2); - -public: - Item_sum_count_distinct(List &list) - :Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0), - force_copy_fields(0), tree(0), count(0), - original(0), always_null(FALSE) - { quick_group= 0; } - Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item) - :Item_sum_int(thd, item), table(item->table), - field_lengths(item->field_lengths), - tmp_table_param(item->tmp_table_param), - force_copy_fields(0), tree(item->tree), count(item->count), - original(item), tree_key_length(item->tree_key_length), - always_null(item->always_null) - {} - ~Item_sum_count_distinct(); - - void cleanup(); - - enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; } - void clear(); - bool add(); - longlong val_int(); - void reset_field() { return ;} // Never called - void update_field() { return ; } // Never called - const char *func_name() const { return "count(distinct "; } - bool setup(THD *thd); - void make_unique(); - Item *copy_or_same(THD* thd); - void no_rows_in_result() {} -}; - - /* Item to get the value of a stored sum function */ class Item_sum_avg; @@ -674,13 +803,18 @@ public: uint prec_increment; uint f_precision, f_scale, dec_bin_size; - Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {} + Item_sum_avg(Item *item_par, bool distinct= FALSE) + :Item_sum_sum(item_par, distinct), count(0) + {} Item_sum_avg(THD *thd, Item_sum_avg *item) :Item_sum_sum(thd, item), count(item->count), prec_increment(item->prec_increment) {} void fix_length_and_dec(); - enum Sumfunctype sum_func () const {return AVG_FUNC;} + enum Sumfunctype sum_func () const + { + return with_distinct ? AVG_DISTINCT_FUNC : AVG_FUNC; + } void clear(); bool add(); double val_real(); @@ -693,7 +827,10 @@ public: Item *result_item(Field *field) { return new Item_avg_field(hybrid_type, this); } void no_rows_in_result() {} - const char *func_name() const { return "avg("; } + const char *func_name() const + { + return with_distinct ? "avg(distinct " : "avg("; + } Item *copy_or_same(THD* thd); Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); void cleanup() diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 05575e2744b..52e8d5d61c2 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -708,7 +708,8 @@ static TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, double read_time); static -TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree); +TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree, + double read_time); static double get_index_only_read_time(const PARAM* param, ha_rows records, int keynr); @@ -2049,7 +2050,7 @@ public: class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN { private: - bool have_min, have_max; + bool have_min, have_max, have_agg_distinct; KEY_PART_INFO *min_max_arg_part; uint group_prefix_len; uint used_key_parts; @@ -2061,11 +2062,13 @@ private: SEL_TREE *range_tree; /* Represents all range predicates in the query. */ SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */ uint param_idx; /* Index of used key in param->key. */ - /* Number of records selected by the ranges in index_tree. */ + bool is_index_scan; /* Use index_next() instead of random read */ public: + /* Number of records selected by the ranges in index_tree. */ ha_rows quick_prefix_records; public: - TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg, + TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg, + bool have_agg_distinct_arg, KEY_PART_INFO *min_max_arg_part_arg, uint group_prefix_len_arg, uint used_key_parts_arg, uint group_key_parts_arg, KEY *index_info_arg, @@ -2074,11 +2077,12 @@ public: SEL_TREE *tree_arg, SEL_ARG *index_tree_arg, uint param_idx_arg, ha_rows quick_prefix_records_arg) : have_min(have_min_arg), have_max(have_max_arg), + have_agg_distinct(have_agg_distinct_arg), min_max_arg_part(min_max_arg_part_arg), group_prefix_len(group_prefix_len_arg), used_key_parts(used_key_parts_arg), group_key_parts(group_key_parts_arg), index_info(index_info_arg), index(index_arg), key_infix_len(key_infix_len_arg), range_tree(tree_arg), - index_tree(index_tree_arg), param_idx(param_idx_arg), + index_tree(index_tree_arg), param_idx(param_idx_arg), is_index_scan(FALSE), quick_prefix_records(quick_prefix_records_arg) { if (key_infix_len) @@ -2088,6 +2092,7 @@ public: QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, MEM_ROOT *parent_alloc); + void use_index_scan() { is_index_scan= TRUE; } }; @@ -2349,7 +2354,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, Try to construct a QUICK_GROUP_MIN_MAX_SELECT. Notice that it can be constructed no matter if there is a range tree. */ - group_trp= get_best_group_min_max(¶m, tree); + group_trp= get_best_group_min_max(¶m, tree, best_read_time); if (group_trp) { param.table->quick_condition_rows= min(group_trp->records, @@ -9048,15 +9053,10 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts, double *read_cost, ha_rows *records); -/* +/** Test if this access method is applicable to a GROUP query with MIN/MAX functions, and if so, construct a new TRP object. - SYNOPSIS - get_best_group_min_max() - param Parameter from test_quick_select - sel_tree Range tree generated by get_mm_tree - DESCRIPTION Test whether a query can be computed via a QUICK_GROUP_MIN_MAX_SELECT. Queries computable via a QUICK_GROUP_MIN_MAX_SELECT must satisfy the @@ -9167,17 +9167,16 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts, - Lift the limitation in condition (B3), that is, make this access method applicable to ROLLUP queries. - RETURN - If mem_root != NULL - - valid TRP_GROUP_MIN_MAX object if this QUICK class can be used for - the query - - NULL o/w. - If mem_root == NULL - - NULL + @param param Parameter from test_quick_select + @param sel_tree Range tree generated by get_mm_tree + @param read_time Best read time so far (=table/index scan time) + @return table read plan + @retval NULL Loose index scan not applicable or mem_root == NULL + @retval !NULL Loose index scan table read plan */ static TRP_GROUP_MIN_MAX * -get_best_group_min_max(PARAM *param, SEL_TREE *tree) +get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) { THD *thd= param->thd; JOIN *join= thd->lex->current_select->join; @@ -9198,25 +9197,33 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) ORDER *tmp_group; Item *item; Item_field *item_field; + bool is_agg_distinct; + List agg_distinct_flds; + DBUG_ENTER("get_best_group_min_max"); /* Perform few 'cheap' tests whether this access method is applicable. */ if (!join) DBUG_RETURN(NULL); /* This is not a select statement. */ if ((join->tables != 1) || /* The query must reference one table. */ - ((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */ - (!join->select_distinct)) || (join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */ DBUG_RETURN(NULL); if (table->s->keys == 0) /* There are no indexes to use. */ DBUG_RETURN(NULL); - /* Analyze the query in more detail. */ - List_iterator select_items_it(join->fields_list); - /* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/ if (join->make_sum_func_list(join->all_fields, join->fields_list, 1)) DBUG_RETURN(NULL); + + List_iterator select_items_it(join->fields_list); + is_agg_distinct = is_indexed_agg_distinct(join, &agg_distinct_flds); + + if ((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */ + (!join->select_distinct) && + !is_agg_distinct) + DBUG_RETURN(NULL); + /* Analyze the query in more detail. */ + if (join->sum_funcs[0]) { Item_sum *min_max_item; @@ -9227,6 +9234,10 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) have_min= TRUE; else if (min_max_item->sum_func() == Item_sum::MAX_FUNC) have_max= TRUE; + else if (min_max_item->sum_func() == Item_sum::COUNT_DISTINCT_FUNC || + min_max_item->sum_func() == Item_sum::SUM_DISTINCT_FUNC || + min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC) + continue; else DBUG_RETURN(NULL); @@ -9243,13 +9254,12 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) DBUG_RETURN(NULL); } } - /* Check (SA5). */ if (join->select_distinct) { while ((item= select_items_it++)) { - if (item->type() != Item::FIELD_ITEM) + if (item->real_item()->type() != Item::FIELD_ITEM) DBUG_RETURN(NULL); } } @@ -9257,7 +9267,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) /* Check (GA4) - that there are no expressions among the group attributes. */ for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next) { - if ((*tmp_group->item)->type() != Item::FIELD_ITEM) + if ((*tmp_group->item)->real_item()->type() != Item::FIELD_ITEM) DBUG_RETURN(NULL); } @@ -9276,6 +9286,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) uint best_param_idx= 0; const uint pk= param->table->s->primary_key; + uint max_key_part; SEL_ARG *cur_index_tree= NULL; ha_rows cur_quick_prefix_records= 0; uint cur_param_idx=MAX_KEY; @@ -9329,6 +9340,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) } } + max_key_part= 0; + used_key_parts_map.clear_all(); /* Check (GA1) for GROUP BY queries. */ @@ -9352,6 +9365,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) { cur_group_prefix_len+= cur_part->store_length; ++cur_group_key_parts; + max_key_part= cur_part - cur_index_info->key_part + 1; + used_key_parts_map.set_bit(max_key_part); } else goto next_index; @@ -9365,14 +9380,26 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) Later group_fields_array of ORDER objects is used to convert the query to a GROUP query. */ - else if (join->select_distinct) + if ((!join->group_list && join->select_distinct) || + is_agg_distinct) { - select_items_it.rewind(); - used_key_parts_map.clear_all(); - uint max_key_part= 0; - while ((item= select_items_it++)) + if (!is_agg_distinct) { - item_field= (Item_field*) item; /* (SA5) already checked above. */ + select_items_it.rewind(); + } + + List_iterator agg_distinct_flds_it (agg_distinct_flds); + while (NULL != (item = (is_agg_distinct ? + (Item *) agg_distinct_flds_it++ : select_items_it++))) + { + /* (SA5) already checked above. */ + item_field= (Item_field*) item->real_item(); + DBUG_ASSERT(item->real_item()->type() == Item::FIELD_ITEM); + + /* not doing loose index scan for derived tables */ + if (!item_field->field) + goto next_index; + /* Find the order of the key part in the index. */ key_part_nr= get_field_keypart(cur_index_info, item_field->field); /* @@ -9381,7 +9408,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ if (used_key_parts_map.is_set(key_part_nr)) continue; - if (key_part_nr < 1 || key_part_nr > join->fields_list.elements) + if (key_part_nr < 1 || + (!is_agg_distinct && key_part_nr > join->fields_list.elements)) goto next_index; cur_part= cur_index_info->key_part + key_part_nr - 1; cur_group_prefix_len+= cur_part->store_length; @@ -9401,10 +9429,6 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) if (all_parts != cur_parts) goto next_index; } - else - { - DBUG_ASSERT(FALSE); - } /* Check (SA2). */ if (min_max_arg_item) @@ -9558,7 +9582,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) /* The query passes all tests, so construct a new TRP object. */ read_plan= new (param->mem_root) - TRP_GROUP_MIN_MAX(have_min, have_max, min_max_arg_part, + TRP_GROUP_MIN_MAX(have_min, have_max, is_agg_distinct, + min_max_arg_part, group_prefix_len, used_key_parts, group_key_parts, index_info, index, key_infix_len, @@ -9572,6 +9597,11 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) read_plan->read_cost= best_read_cost; read_plan->records= best_records; + if (read_time < best_read_cost && is_agg_distinct) + { + read_plan->read_cost= 0; + read_plan->use_index_scan(); + } DBUG_PRINT("info", ("Returning group min/max plan: cost: %g, records: %lu", @@ -10077,11 +10107,12 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows, quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table, param->thd->lex->current_select->join, - have_min, have_max, min_max_arg_part, + have_min, have_max, + have_agg_distinct, min_max_arg_part, group_prefix_len, group_key_parts, used_key_parts, index_info, index, read_cost, records, key_infix_len, - key_infix, parent_alloc); + key_infix, parent_alloc, is_index_scan); if (!quick) DBUG_RETURN(NULL); @@ -10161,6 +10192,9 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows, key_infix_len Length of the key infix appended to the group prefix key_infix Infix of constants from equality predicates parent_alloc Memory pool for this and quick_prefix_select data + is_index_scan get the next different key not by jumping on it via + index read, but by scanning until the end of the + rows with equal key value. RETURN None @@ -10168,20 +10202,22 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows, QUICK_GROUP_MIN_MAX_SELECT:: QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg, - bool have_max_arg, + bool have_max_arg, bool have_agg_distinct_arg, KEY_PART_INFO *min_max_arg_part_arg, uint group_prefix_len_arg, uint group_key_parts_arg, uint used_key_parts_arg, KEY *index_info_arg, uint use_index, double read_cost_arg, ha_rows records_arg, uint key_infix_len_arg, - uchar *key_infix_arg, MEM_ROOT *parent_alloc) + uchar *key_infix_arg, MEM_ROOT *parent_alloc, + bool is_index_scan_arg) :join(join_arg), index_info(index_info_arg), group_prefix_len(group_prefix_len_arg), group_key_parts(group_key_parts_arg), have_min(have_min_arg), - have_max(have_max_arg), seen_first_key(FALSE), - min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg), - key_infix_len(key_infix_len_arg), min_functions_it(NULL), - max_functions_it(NULL) + have_max(have_max_arg), have_agg_distinct(have_agg_distinct_arg), + seen_first_key(FALSE), min_max_arg_part(min_max_arg_part_arg), + key_infix(key_infix_arg), key_infix_len(key_infix_len_arg), + min_functions_it(NULL), max_functions_it(NULL), + is_index_scan(is_index_scan_arg) { head= table; file= head->file; @@ -10744,6 +10780,56 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max() } +/** + Find the next different key value by skiping all the rows with the same key + value. + + Implements a specialized loose index access method for queries + containing aggregate functions with distinct of the form: + SELECT [SUM|COUNT|AVG](DISTINCT a,...) FROM t + This method comes to replace the index scan + Unique class + (distinct selection) for loose index scan that visits all the rows of a + covering index instead of jumping in the begining of each group. + TODO: Placeholder function. To be replaced by a handler API call + + @param is_index_scan hint to use index scan instead of random index read + to find the next different value. + @param file table handler + @param key_part group key to compare + @param record row data + @param group_prefix current key prefix data + @param group_prefix_len length of the current key prefix data + @param group_key_parts number of the current key prefix columns + @return status + @retval 0 success + @retval !0 failure +*/ + +static int index_next_different (bool is_index_scan, handler *file, + KEY_PART_INFO *key_part, uchar * record, + const uchar * group_prefix, + uint group_prefix_len, + uint group_key_parts) +{ + if (is_index_scan) + { + int result= 0; + + while (!key_cmp (key_part, group_prefix, group_prefix_len)) + { + result= file->index_next(record); + if (result) + return(result); + } + return result; + } + else + return file->index_read_map(record, group_prefix, + make_prev_keypart_map(group_key_parts), + HA_READ_AFTER_KEY); +} + + /* Determine the prefix of the next group. @@ -10790,9 +10876,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix() else { /* Load the first key in this group into record. */ - result= file->index_read_map(record, group_prefix, - make_prev_keypart_map(group_key_parts), - HA_READ_AFTER_KEY); + result= index_next_different (is_index_scan, file, index_info->key_part, + record, group_prefix, group_prefix_len, + group_key_parts); if (result) DBUG_RETURN(result); } diff --git a/sql/opt_range.h b/sql/opt_range.h index 8d2ba1bb0a6..393ffcb2115 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -616,6 +616,7 @@ private: uchar *last_prefix; /* Prefix of the last group for detecting EOF. */ bool have_min; /* Specify whether we are computing */ bool have_max; /* a MIN, a MAX, or both. */ + bool have_agg_distinct;/* aggregate_function(DISTINCT ...). */ bool seen_first_key; /* Denotes whether the first key was retrieved.*/ KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */ /* of all MIN/MAX functions. */ @@ -629,6 +630,11 @@ private: List *max_functions; List_iterator *min_functions_it; List_iterator *max_functions_it; + /* + Use index scan to get the next different key instead of jumping into it + through index read + */ + bool is_index_scan; public: /* The following two members are public to allow easy access from @@ -646,12 +652,13 @@ private: void update_max_result(); public: QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min, - bool have_max, KEY_PART_INFO *min_max_arg_part, + bool have_max, bool have_agg_distinct, + KEY_PART_INFO *min_max_arg_part, uint group_prefix_len, uint group_key_parts, uint used_key_parts, KEY *index_info, uint use_index, double read_cost, ha_rows records, uint key_infix_len, uchar *key_infix, MEM_ROOT - *parent_alloc); + *parent_alloc, bool is_index_scan); ~QUICK_GROUP_MIN_MAX_SELECT(); bool add_range(SEL_ARG *sel_range); void update_key_stat(); @@ -667,6 +674,12 @@ public: #ifndef DBUG_OFF void dbug_dump(int indent, bool verbose); #endif + bool is_agg_distinct() { return have_agg_distinct; } + virtual void append_loose_scan_type(String *str) + { + if (is_index_scan) + str->append(STRING_WITH_LEN(" (scanning)")); + } }; diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 8e7265ba1ad..d995faf1ab6 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -355,10 +355,13 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) const_result= 0; break; } + item_sum->set_aggregator (item_sum->with_distinct ? + Aggregator::DISTINCT_AGGREGATOR : + Aggregator::SIMPLE_AGGREGATOR); if (!count) { /* If count == 0, then we know that is_exact_count == TRUE. */ - ((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */ + ((Item_sum_min*) item_sum)->aggregator_clear(); /* Set to NULL. */ } else ((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */ @@ -443,10 +446,13 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) const_result= 0; break; } + item_sum->set_aggregator (item_sum->with_distinct ? + Aggregator::DISTINCT_AGGREGATOR : + Aggregator::SIMPLE_AGGREGATOR); if (!count) { /* If count != 1, then we know that is_exact_count == TRUE. */ - ((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */ + ((Item_sum_max*) item_sum)->aggregator_clear(); /* Set to NULL. */ } else ((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */ diff --git a/sql/sql_class.h b/sql/sql_class.h index e845b5a727c..4874801e380 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -54,6 +54,7 @@ class Reprepare_observer { public: + Reprepare_observer() {} /** Check if a change of metadata is OK. In future the signature of this method may be extended to accept the old diff --git a/sql/sql_select.cc b/sql/sql_select.cc index db3a73aec74..3e2d85e4951 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -222,6 +222,7 @@ static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table); static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end); static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab); static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr); +static bool prepare_sum_aggregators(Item_sum **func_ptr, bool need_distinct); static bool init_sum_functions(Item_sum **func, Item_sum **end); static bool update_sum_func(Item_sum **func); static void select_describe(JOIN *join, bool need_tmp_table,bool need_order, @@ -1232,7 +1233,11 @@ JOIN::optimize() if (test_if_subpart(group_list, order) || (!group_list && tmp_table_param.sum_func_count)) + { order=0; + if (is_indexed_agg_distinct(this, NULL)) + sort_and_group= 0; + } // Can't use sort on head table if using row cache if (full_join) @@ -1410,8 +1415,16 @@ JOIN::optimize() single table queries, thus it is sufficient to test only the first join_tab element of the plan for its access method. */ + bool need_distinct= TRUE; if (join_tab->is_using_loose_index_scan()) + { tmp_table_param.precomputed_group_by= TRUE; + if (join_tab->is_using_agg_loose_index_scan()) + { + need_distinct= FALSE; + tmp_table_param.precomputed_group_by= FALSE; + } + } /* Create a tmp table if distinct or if the sort is too complicated */ if (need_tmp) @@ -1472,6 +1485,7 @@ JOIN::optimize() HA_POS_ERROR, HA_POS_ERROR, FALSE) || alloc_group_fields(this, group_list) || make_sum_func_list(all_fields, fields_list, 1) || + prepare_sum_aggregators(sum_funcs, need_distinct) || setup_sum_funcs(thd, sum_funcs)) { DBUG_RETURN(1); @@ -1481,6 +1495,7 @@ JOIN::optimize() else { if (make_sum_func_list(all_fields, fields_list, 0) || + prepare_sum_aggregators(sum_funcs, need_distinct) || setup_sum_funcs(thd, sum_funcs)) { DBUG_RETURN(1); @@ -1953,7 +1968,9 @@ JOIN::exec() } } if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, - 1, TRUE)) + 1, TRUE) || + prepare_sum_aggregators(curr_join->sum_funcs, + !curr_join->join_tab->is_using_agg_loose_index_scan())) DBUG_VOID_RETURN; curr_join->group_list= 0; if (!curr_join->sort_and_group && @@ -2056,6 +2073,8 @@ JOIN::exec() if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, 1, TRUE) || + prepare_sum_aggregators (curr_join->sum_funcs, !curr_join->join_tab || + !curr_join->join_tab->is_using_agg_loose_index_scan()) || setup_sum_funcs(curr_join->thd, curr_join->sum_funcs) || thd->is_fatal_error) DBUG_VOID_RETURN; @@ -3937,6 +3956,82 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array) } +/** + Check for the presence of AGGFN(DISTINCT a) queries that may be subject + to loose index scan. + + + Check if the query is a subject to AGGFN(DISTINCT) using loose index scan + (QUICK_GROUP_MIN_MAX_SELECT). + Optionally (if out_args is supplied) will push the arguments of + AGGFN(DISTINCT) to the list + + @param join the join to check + @param[out] out_args list of aggregate function arguments + @return does the query qualify for indexed AGGFN(DISTINCT) + @retval true it does + @retval false AGGFN(DISTINCT) must apply distinct in it. +*/ + +bool +is_indexed_agg_distinct(JOIN *join, List *out_args) +{ + Item_sum **sum_item_ptr; + bool result= false; + + if (join->tables != 1 || /* reference more than 1 table */ + join->select_distinct || /* or a DISTINCT */ + join->select_lex->olap == ROLLUP_TYPE) /* Check (B3) for ROLLUP */ + return false; + + if (join->make_sum_func_list(join->all_fields, join->fields_list, 1)) + return false; + + for (sum_item_ptr= join->sum_funcs; *sum_item_ptr; sum_item_ptr++) + { + Item_sum *sum_item= *sum_item_ptr; + Item *expr; + /* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */ + switch (sum_item->sum_func()) + { + case Item_sum::MIN_FUNC: + case Item_sum::MAX_FUNC: + continue; + case Item_sum::COUNT_DISTINCT_FUNC: + break; + case Item_sum::AVG_DISTINCT_FUNC: + case Item_sum::SUM_DISTINCT_FUNC: + if (sum_item->get_arg_count() == 1) + break; + /* fall through */ + default: return false; + } + /* + We arrive here for every COUNT(DISTINCT),AVG(DISTINCT) or SUM(DISTINCT). + Collect the arguments of the aggregate functions to a list. + We don't worry about duplicates as these will be sorted out later in + get_best_group_min_max + */ + for (uint i= 0; i < sum_item->get_arg_count(); i++) + { + expr= sum_item->get_arg(i); + /* The AGGFN(DISTINCT) arg is not an attribute? */ + if (expr->real_item()->type() != Item::FIELD_ITEM) + return false; + + /* + If we came to this point the AGGFN(DISTINCT) loose index scan + optimization is applicable + */ + if (out_args) + out_args->push_back((Item_field *) expr); + result= true; + } + } + return result; +} + + /** Discover the indexes that can be used for GROUP BY or DISTINCT queries. @@ -3979,6 +4074,10 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab) item->walk(&Item::collect_item_field_processor, 0, (uchar*) &indexed_fields); } + else if (is_indexed_agg_distinct(join, &indexed_fields)) + { + join->sort_and_group= 1; + } else return; @@ -10377,6 +10476,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List &field_list) bzero(share, sizeof(*share)); table->field= field; table->s= share; + table->temp_pool_slot= MY_BIT_NONE; share->blob_field= blob_field; share->fields= field_count; share->blob_ptr_size= portable_sizeof_char_ptr; @@ -14532,7 +14632,7 @@ setup_new_fields(THD *thd, List &fields, optimize away 'order by'. */ -static ORDER * +ORDER * create_distinct_group(THD *thd, Item **ref_pointer_array, ORDER *order_list, List &fields, List &all_fields, @@ -15334,7 +15434,22 @@ static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr) DBUG_ENTER("setup_sum_funcs"); while ((func= *(func_ptr++))) { - if (func->setup(thd)) + if (func->aggregator_setup(thd)) + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + + +static bool prepare_sum_aggregators(Item_sum **func_ptr, bool need_distinct) +{ + Item_sum *func; + DBUG_ENTER("setup_sum_funcs"); + while ((func= *(func_ptr++))) + { + if (func->set_aggregator(need_distinct && func->with_distinct ? + Aggregator::DISTINCT_AGGREGATOR : + Aggregator::SIMPLE_AGGREGATOR)) DBUG_RETURN(TRUE); } DBUG_RETURN(FALSE); @@ -15384,7 +15499,7 @@ init_sum_functions(Item_sum **func_ptr, Item_sum **end_ptr) /* If rollup, calculate the upper sum levels */ for ( ; *func_ptr ; func_ptr++) { - if ((*func_ptr)->add()) + if ((*func_ptr)->aggregator_add()) return 1; } return 0; @@ -15396,7 +15511,7 @@ update_sum_func(Item_sum **func_ptr) { Item_sum *func; for (; (func= (Item_sum*) *func_ptr) ; func_ptr++) - if (func->add()) + if (func->aggregator_add()) return 1; return 0; } @@ -16313,7 +16428,12 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (key_read) { if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) + { + QUICK_GROUP_MIN_MAX_SELECT *qgs= + (QUICK_GROUP_MIN_MAX_SELECT *) tab->select->quick; extra.append(STRING_WITH_LEN("; Using index for group-by")); + qgs->append_loose_scan_type(&extra); + } else extra.append(STRING_WITH_LEN("; Using index")); } diff --git a/sql/sql_select.h b/sql/sql_select.h index a0366d47149..bb751c600ed 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -218,6 +218,11 @@ typedef struct st_join_table { (select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)); } + bool is_using_agg_loose_index_scan () + { + return (is_using_loose_index_scan() && + ((QUICK_GROUP_MIN_MAX_SELECT *)select->quick)->is_agg_distinct()); + } } JOIN_TAB; enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool @@ -564,6 +569,8 @@ Field* create_tmp_field_from_field(THD *thd, Field* org_field, const char *name, TABLE *table, Item_field *item, uint convert_blob_length); +bool is_indexed_agg_distinct(JOIN *join, List *out_args); + /* functions from opt_sum.cc */ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order); int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 329158b7750..e7193d76d4e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8128,7 +8128,7 @@ sum_expr: } | AVG_SYM '(' DISTINCT in_sum_expr ')' { - $$= new (YYTHD->mem_root) Item_sum_avg_distinct($4); + $$= new (YYTHD->mem_root) Item_sum_avg($4, TRUE); if ($$ == NULL) MYSQL_YYABORT; } @@ -8171,7 +8171,7 @@ sum_expr: { Select->in_sum_expr--; } ')' { - $$= new (YYTHD->mem_root) Item_sum_count_distinct(* $5); + $$= new (YYTHD->mem_root) Item_sum_count(* $5); if ($$ == NULL) MYSQL_YYABORT; } @@ -8236,7 +8236,7 @@ sum_expr: } | SUM_SYM '(' DISTINCT in_sum_expr ')' { - $$= new (YYTHD->mem_root) Item_sum_sum_distinct($4); + $$= new (YYTHD->mem_root) Item_sum_sum($4, TRUE); if ($$ == NULL) MYSQL_YYABORT; } From fbe6a4a7ddd4f49c21db7cc87fcdc99f48514ed3 Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Mon, 28 Sep 2009 13:44:45 +0200 Subject: [PATCH 020/274] Disabling tests that are not relevant after BUG#40116, these will be enabled when WL#2867 or associated fixes for 5.1 is added to solve the problem. --- .../rpl_ndb/r/rpl_ndb_mixed_tables.result | 40 ------------------- .../suite/rpl_ndb/t/rpl_ndb_mixed_tables.test | 24 +++++++++++ 2 files changed, 24 insertions(+), 40 deletions(-) diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_tables.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_tables.result index 92fda774da5..43efc10c2e1 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_tables.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_tables.result @@ -111,22 +111,10 @@ INSERT INTO innodb_ndb VALUES (12); COMMIT; ---- ROLLBACK ---- BEGIN; -INSERT INTO myisam_innodb VALUES (13); -INSERT INTO myisam_innodb VALUES (14); -ROLLBACK; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back -BEGIN; INSERT INTO innodb_myisam VALUES (15); INSERT INTO innodb_myisam VALUES (16); ROLLBACK; BEGIN; -INSERT INTO myisam_ndb VALUES (17); -INSERT INTO myisam_ndb VALUES (18); -ROLLBACK; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back -BEGIN; INSERT INTO ndb_myisam VALUES (19); INSERT INTO ndb_myisam VALUES (20); ROLLBACK; @@ -167,22 +155,10 @@ INSERT INTO innodb_ndb VALUES (36); COMMIT; ---- ROLLBACK ---- BEGIN; -INSERT INTO myisam_innodb VALUES (37); -INSERT INTO myisam_innodb VALUES (38); -ROLLBACK; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back -BEGIN; INSERT INTO innodb_myisam VALUES (39); INSERT INTO innodb_myisam VALUES (40); ROLLBACK; BEGIN; -INSERT INTO myisam_ndb VALUES (41); -INSERT INTO myisam_ndb VALUES (42); -ROLLBACK; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back -BEGIN; INSERT INTO ndb_myisam VALUES (43); INSERT INTO ndb_myisam VALUES (44); ROLLBACK; @@ -209,25 +185,15 @@ INSERT INTO innodb_ndb VALUES (59); INSERT INTO innodb_ndb VALUES (60); ==== AUTOCOMMIT=0, single statements, myisam on master ==== SET AUTOCOMMIT = 0; -INSERT INTO myisam_innodb VALUES (61); -INSERT INTO myisam_innodb VALUES (62); -INSERT INTO myisam_ndb VALUES (63); -INSERT INTO myisam_ndb VALUES (64); ==== Show results ==== SELECT * FROM myisam_innodb ORDER BY a; a 1 2 -13 -14 25 26 -37 -38 49 50 -61 -62 SELECT * FROM innodb_myisam ORDER BY a; a 3 @@ -240,16 +206,10 @@ SELECT * FROM myisam_ndb ORDER BY a; a 5 6 -17 -18 29 30 -41 -42 53 54 -63 -64 SELECT * FROM ndb_myisam ORDER BY a; a 7 diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables.test index 7d7cd5770cf..a20e42f1b24 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_mixed_tables.test @@ -134,11 +134,15 @@ connection master; --echo ---- ROLLBACK ---- +# This test does not work in ROW mode after the changes introduced in +# BUG#40116. After WL#2687 is pushed, Tests should be added again. +--disable_parsing BEGIN; INSERT INTO myisam_innodb VALUES (13); INSERT INTO myisam_innodb VALUES (14); ROLLBACK; sync_slave_with_master; +--enable_parsing connection master; BEGIN; INSERT INTO innodb_myisam VALUES (15); @@ -147,12 +151,17 @@ ROLLBACK; sync_slave_with_master; connection master; +# This test does not work in ROW mode after the changes introduced in +# BUG#40116. After WL#2687 is pushed, these tests should be enabled +# again. +--disable_parsing BEGIN; INSERT INTO myisam_ndb VALUES (17); INSERT INTO myisam_ndb VALUES (18); ROLLBACK; sync_slave_with_master; connection master; +--enable_parsing BEGIN; INSERT INTO ndb_myisam VALUES (19); INSERT INTO ndb_myisam VALUES (20); @@ -221,12 +230,17 @@ connection master; --echo ---- ROLLBACK ---- +# This test does not work in ROW mode after the changes introduced in +# BUG#40116. After WL#2687 is pushed, these tests should be enabled +# again. +--disable_parsing BEGIN; INSERT INTO myisam_innodb VALUES (37); INSERT INTO myisam_innodb VALUES (38); ROLLBACK; sync_slave_with_master; connection master; +--enable_parsing BEGIN; INSERT INTO innodb_myisam VALUES (39); INSERT INTO innodb_myisam VALUES (40); @@ -234,12 +248,17 @@ ROLLBACK; sync_slave_with_master; connection master; +# This test does not work in ROW mode after the changes introduced in +# BUG#40116. After WL#2687 is pushed, these tests should be enabled +# again. +--disable_parsing BEGIN; INSERT INTO myisam_ndb VALUES (41); INSERT INTO myisam_ndb VALUES (42); ROLLBACK; sync_slave_with_master; connection master; +--enable_parsing BEGIN; INSERT INTO ndb_myisam VALUES (43); INSERT INTO ndb_myisam VALUES (44); @@ -295,6 +314,10 @@ connection master; SET AUTOCOMMIT = 0; +# These tests do not work in ROW mode after the changes introduced in +# BUG#40116. After WL#2687 is pushed, these tests should be enabled +# again. +--disable_parsing # This tests BUG#29288. INSERT INTO myisam_innodb VALUES (61); INSERT INTO myisam_innodb VALUES (62); @@ -305,6 +328,7 @@ INSERT INTO myisam_ndb VALUES (63); INSERT INTO myisam_ndb VALUES (64); sync_slave_with_master; connection master; +--enable_parsing --echo ==== Show results ==== From f0886a4d9dfc36e92f7254c958ec73476704c4d4 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 29 Sep 2009 00:04:20 +0100 Subject: [PATCH 021/274] BUG#28777, WL#4293: SHOW BINLOG EVENTS does not work on relay log files NOTE: this is the backport to next-mr. SHOW BINLOG EVENTS does not work with relay log files. If issuing "SHOW BINLOG EVENTS IN 'relay-log.000001'" in a non-empty relay log file (relay-log.000001), mysql reports empty set. This patch addresses this issue by extending the SHOW command with RELAYLOG. Events in relay log files can now be inspected by issuing SHOW RELAYLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]. mysql-test/extra/rpl_tests/rpl_show_relaylog_events.inc: Shared part of the test case. mysql-test/include/show_binlog_events.inc: Added options $binary_log_file, $binary_log_limit_row, $binary_log_limit_offset so that show_binlog_events can take same parameters as SHOW BINLOG EVENTS does. mysql-test/include/show_relaylog_events.inc: Clone of show_binlog_events for relaylog events. mysql-test/suite/rpl/t/rpl_row_show_relaylog_events.test: Test case for row based replication. mysql-test/suite/rpl/t/rpl_stm_mix_show_relaylog_events.test: Test case for statement and mixed mode replication. sql/lex.h: Added RELAYLOG symbol. sql/mysqld.cc: Added "show_relaylog_events" to status_vars. sql/sp_head.cc: Set SQLCOM_SHOW_RELAYLOG_EVENTS to return flags= sp_head::MULTI_RESULTS; in sp_get_flags_for_command as SQLCOM_SHOW_BINLOG_EVENTS does. sql/sql_lex.h: Added sql_command SQLCOM_SHOW_RELAYLOG_EVENTS to lex enum_sql_command. sql/sql_parse.cc: Added handling of SQLCOM_SHOW_RELAYLOG_EVENTS. sql/sql_repl.cc: mysql_show_binlog_events set to choose the log file to use based on the command issued (SHOW BINLOG|RELAYLOG EVENTS). sql/sql_yacc.yy: Added RELAYLOG to the grammar. --- .../rpl_tests/rpl_show_relaylog_events.inc | 121 ++++++++ mysql-test/include/show_binlog_events.inc | 27 +- mysql-test/include/show_relaylog_events.inc | 35 +++ .../rpl/r/rpl_row_show_relaylog_events.result | 274 ++++++++++++++++++ .../r/rpl_stm_mix_show_relaylog_events.result | 148 ++++++++++ .../rpl/t/rpl_row_show_relaylog_events.test | 18 ++ .../t/rpl_stm_mix_show_relaylog_events.test | 18 ++ sql/lex.h | 1 + sql/mysqld.cc | 1 + sql/sp_head.cc | 1 + sql/sql_lex.h | 2 +- sql/sql_parse.cc | 1 + sql/sql_repl.cc | 37 ++- sql/sql_yacc.yy | 7 + 14 files changed, 679 insertions(+), 12 deletions(-) create mode 100644 mysql-test/extra/rpl_tests/rpl_show_relaylog_events.inc create mode 100644 mysql-test/include/show_relaylog_events.inc create mode 100644 mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result create mode 100644 mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result create mode 100644 mysql-test/suite/rpl/t/rpl_row_show_relaylog_events.test create mode 100644 mysql-test/suite/rpl/t/rpl_stm_mix_show_relaylog_events.test diff --git a/mysql-test/extra/rpl_tests/rpl_show_relaylog_events.inc b/mysql-test/extra/rpl_tests/rpl_show_relaylog_events.inc new file mode 100644 index 00000000000..50036e564a7 --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_show_relaylog_events.inc @@ -0,0 +1,121 @@ +-- connection master + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (3); +INSERT INTO t1 VALUES (4); +INSERT INTO t1 VALUES (5); +INSERT INTO t1 VALUES (6); + +-- echo [MASTER] ********* SOW BINLOG EVENTS IN ... ********* +let $binary_log_file= master-bin.000001; +-- source include/show_binlog_events.inc + +-- echo [MASTER] ********* SOW BINLOG EVENTS ********* +let $binary_log_file= ; +-- source include/show_binlog_events.inc + +-- echo [MASTER] ********* SOW BINLOG EVENTS ... LIMIT rows ********* +let $binary_log_file= ; +let $binary_log_limit_row= 3; +-- source include/show_binlog_events.inc + +-- echo [MASTER] ********* SOW BINLOG EVENTS ... LIMIT offset,rows ********* +let $binary_log_file= ; +let $binary_log_limit_row= 3; +let $binary_log_limit_offset= 1; +-- source include/show_binlog_events.inc + +# clear show_binlog_event/show_relaylog_events parameters +let $binary_log_file= ; +let $binary_log_limit_row= ; +let $binary_log_limit_offset= ; + +-- sync_slave_with_master + +-- echo [SLAVE] ********* SOW BINLOG EVENTS IN ... ********* +let $binary_log_file= slave-bin.000001; +-- source include/show_binlog_events.inc + +-- echo [SLAVE] ********* SOW BINLOG EVENTS ********* +let $binary_log_file= ; +-- source include/show_binlog_events.inc + +-- echo [SLAVE] ********* SOW BINLOG EVENTS ... LIMIT rows ********* +let $binary_log_file= ; +let $binary_log_limit_row= 3; +-- source include/show_binlog_events.inc + +-- echo [SLAVE] ********* SOW BINLOG EVENTS ... LIMIT offset,rows ********* +let $binary_log_file= ; +let $binary_log_limit_row= 3; +let $binary_log_limit_offset= 1; +-- source include/show_binlog_events.inc + +# clear show_binlog_event/show_relaylog_events parameters +let $binary_log_file= ; +let $binary_log_limit_row= ; +let $binary_log_limit_offset= ; + +-- echo [SLAVE] ********* SOW RELAYLOG EVENTS IN ... ********* +let $binary_log_file= slave-relay-bin.000003; +-- source include/show_relaylog_events.inc + +-- echo [SLAVE] ********* SOW RELAYLOG EVENTS ********* +let $binary_log_file= ; +-- source include/show_relaylog_events.inc + +-- echo [MASTER] ********* SOW RELAYLOG EVENTS ... LIMIT rows ********* +let $binary_log_file= slave-relay-bin.000003; +let $binary_log_limit_row= 3; +let $binary_log_limit_offset= ; +-- source include/show_relaylog_events.inc + +-- echo [MASTER] ********* SOW RELAYLOG EVENTS ... LIMIT offset,rows ********* +let $binary_log_file= slave-relay-bin.000003; +let $binary_log_limit_offset= 1; +let $binary_log_limit_row= 3; +-- source include/show_relaylog_events.inc + +FLUSH LOGS; + +-- connection master +FLUSH LOGS; +DROP TABLE t1; + +# clear show_binlog_event/show_relaylog_events parameters +let $binary_log_file= ; +let $binary_log_limit_row= ; +let $binary_log_limit_offset= ; + +-- echo [MASTER] ********* SOW BINLOG EVENTS IN ... ********* +let $binary_log_file= master-bin.000002; +-- source include/show_binlog_events.inc + +-- echo [MASTER] ********* SOW BINLOG EVENTS ********* +let $binary_log_file= ; +-- source include/show_binlog_events.inc + +-- sync_slave_with_master + +-- echo [SLAVE] ********* SOW BINLOG EVENTS IN ... ********* +let $binary_log_file= slave-bin.000002; +-- source include/show_binlog_events.inc + +-- echo [SLAVE] ********* SOW BINLOG EVENTS ********* +let $binary_log_file= ; +-- source include/show_binlog_events.inc + +-- echo [SLAVE] ********* SOW RELAYLOG EVENTS IN ... ********* +let $binary_log_file= slave-relay-bin.000005; +-- source include/show_relaylog_events.inc + +-- echo [SLAVE] ********* SOW RELAYLOG EVENTS ********* +let $binary_log_file= ; +-- source include/show_relaylog_events.inc + +# clear show_binlog_event/show_relaylog_events parameters +let $binary_log_name= ; +let $binary_log_limit_row= ; +let $binary_log_limit_offset= ; diff --git a/mysql-test/include/show_binlog_events.inc b/mysql-test/include/show_binlog_events.inc index 68f913a16a3..353ee0e3ce9 100644 --- a/mysql-test/include/show_binlog_events.inc +++ b/mysql-test/include/show_binlog_events.inc @@ -1,10 +1,35 @@ # $binlog_start can be set by caller or take a default value +# $binary_log_file the name of the log file show +# $binary_log_limit_row - sets the number of binlog rows to be returned +# $binary_log_limit_offset - sets the offset where to start returning events + +let $show_binlog_events= show binlog events; if (!$binlog_start) { + # defaults to chop the first event in the binary log let $binlog_start=106; } + +if (!`SELECT '$binary_log_file' = ''`) +{ + let $show_binlog_events= $show_binlog_events in '$binary_log_file'; +} +let $show_binlog_events= $show_binlog_events from $binlog_start; + +if ($binary_log_limit_row) +{ + let $limit= limit; + if ($binary_log_limit_offset) + { + let $limit= $limit $binary_log_limit_offset, ; + } + + let $limit= $limit $binary_log_limit_row; + let $show_binlog_events= $show_binlog_events $limit; +} + --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $binlog_start --replace_column 2 # 4 # 5 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/ ---eval show binlog events from $binlog_start +--eval $show_binlog_events diff --git a/mysql-test/include/show_relaylog_events.inc b/mysql-test/include/show_relaylog_events.inc new file mode 100644 index 00000000000..6f63b055d58 --- /dev/null +++ b/mysql-test/include/show_relaylog_events.inc @@ -0,0 +1,35 @@ +# $binlog_start can be set by caller or take a default value +# $binary_log_file the name of the log file show +# $binary_log_limit_row - sets the number of binlog rows to be returned +# $binary_log_limit_offset - sets the offset where to start returning events + +let $show_binlog_events= show relaylog events; + +if (!$binlog_start) +{ + # defaults to chop the first event in the binary log + let $binlog_start=106; +} + +if (!`SELECT '$binary_log_file' = ''`) +{ + let $show_binlog_events= $show_binlog_events in '$binary_log_file'; +} +let $show_binlog_events= $show_binlog_events from $binlog_start; + +if ($binary_log_limit_row) +{ + let $limit= limit; + if ($binary_log_limit_offset) + { + let $limit= $limit $binary_log_limit_offset, ; + } + + let $limit= $limit $binary_log_limit_row; + let $show_binlog_events= $show_binlog_events $limit; +} + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $binlog_start +--replace_column 2 # 4 # 5 # +--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/ /Server ver:.*$/SERVER_VERSION, BINLOG_VERSION/ +--eval $show_binlog_events diff --git a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result new file mode 100644 index 00000000000..461ab14a93a --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result @@ -0,0 +1,274 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (3); +INSERT INTO t1 VALUES (4); +INSERT INTO t1 VALUES (5); +INSERT INTO t1 VALUES (6); +[MASTER] ********* SOW BINLOG EVENTS IN ... ********* +show binlog events in 'master-bin.000001' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +[MASTER] ********* SOW BINLOG EVENTS ********* +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +[MASTER] ********* SOW BINLOG EVENTS ... LIMIT rows ********* +show binlog events from limit 3; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +[MASTER] ********* SOW BINLOG EVENTS ... LIMIT offset,rows ********* +show binlog events from limit 1, 3; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +[SLAVE] ********* SOW BINLOG EVENTS IN ... ********* +show binlog events in 'slave-bin.000001' from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +[SLAVE] ********* SOW BINLOG EVENTS ********* +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +[SLAVE] ********* SOW BINLOG EVENTS ... LIMIT rows ********* +show binlog events from limit 3; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +[SLAVE] ********* SOW BINLOG EVENTS ... LIMIT offset,rows ********* +show binlog events from limit 1, 3; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +[SLAVE] ********* SOW RELAYLOG EVENTS IN ... ********* +show relaylog events in 'slave-relay-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 +slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-relay-bin.000003 # Query # # BEGIN +slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000003 # Query # # COMMIT +slave-relay-bin.000003 # Query # # BEGIN +slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000003 # Query # # COMMIT +slave-relay-bin.000003 # Query # # BEGIN +slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000003 # Query # # COMMIT +slave-relay-bin.000003 # Query # # BEGIN +slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000003 # Query # # COMMIT +slave-relay-bin.000003 # Query # # BEGIN +slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000003 # Query # # COMMIT +slave-relay-bin.000003 # Query # # BEGIN +slave-relay-bin.000003 # Table_map # # table_id: # (test.t1) +slave-relay-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F +slave-relay-bin.000003 # Query # # COMMIT +[SLAVE] ********* SOW RELAYLOG EVENTS ********* +show relaylog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000002 # Rotate # # slave-relay-bin.000003;pos=4 +[MASTER] ********* SOW RELAYLOG EVENTS ... LIMIT rows ********* +show relaylog events in 'slave-relay-bin.000003' from limit 3; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 +slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) +[MASTER] ********* SOW RELAYLOG EVENTS ... LIMIT offset,rows ********* +show relaylog events in 'slave-relay-bin.000003' from limit 1, 3; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-relay-bin.000003 # Query # # BEGIN +FLUSH LOGS; +FLUSH LOGS; +DROP TABLE t1; +[MASTER] ********* SOW BINLOG EVENTS IN ... ********* +show binlog events in 'master-bin.000002' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Query # # use `test`; DROP TABLE t1 +[MASTER] ********* SOW BINLOG EVENTS ********* +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Rotate # # master-bin.000002;pos=4 +[SLAVE] ********* SOW BINLOG EVENTS IN ... ********* +show binlog events in 'slave-bin.000002' from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Query # # use `test`; DROP TABLE t1 +[SLAVE] ********* SOW BINLOG EVENTS ********* +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Query # # BEGIN +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Rotate # # slave-bin.000002;pos=4 +[SLAVE] ********* SOW RELAYLOG EVENTS IN ... ********* +show relaylog events in 'slave-relay-bin.000005' from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000005 # Rotate # # slave-relay-bin.000006;pos=4 +[SLAVE] ********* SOW RELAYLOG EVENTS ********* +show relaylog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000005 # Rotate # # slave-relay-bin.000006;pos=4 diff --git a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result new file mode 100644 index 00000000000..512a72c3040 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result @@ -0,0 +1,148 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (3); +INSERT INTO t1 VALUES (4); +INSERT INTO t1 VALUES (5); +INSERT INTO t1 VALUES (6); +[MASTER] ********* SOW BINLOG EVENTS IN ... ********* +show binlog events in 'master-bin.000001' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (5) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (6) +[MASTER] ********* SOW BINLOG EVENTS ********* +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (5) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (6) +[MASTER] ********* SOW BINLOG EVENTS ... LIMIT rows ********* +show binlog events from limit 3; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +[MASTER] ********* SOW BINLOG EVENTS ... LIMIT offset,rows ********* +show binlog events from limit 1, 3; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +[SLAVE] ********* SOW BINLOG EVENTS IN ... ********* +show binlog events in 'slave-bin.000001' from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (5) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (6) +[SLAVE] ********* SOW BINLOG EVENTS ********* +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (5) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (6) +[SLAVE] ********* SOW BINLOG EVENTS ... LIMIT rows ********* +show binlog events from limit 3; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +[SLAVE] ********* SOW BINLOG EVENTS ... LIMIT offset,rows ********* +show binlog events from limit 1, 3; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +[SLAVE] ********* SOW RELAYLOG EVENTS IN ... ********* +show relaylog events in 'slave-relay-bin.000003' from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 +slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (1) +slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (2) +slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (3) +slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (4) +slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (5) +slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (6) +[SLAVE] ********* SOW RELAYLOG EVENTS ********* +show relaylog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000002 # Rotate # # slave-relay-bin.000003;pos=4 +[MASTER] ********* SOW RELAYLOG EVENTS ... LIMIT rows ********* +show relaylog events in 'slave-relay-bin.000003' from limit 3; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4 +slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) +[MASTER] ********* SOW RELAYLOG EVENTS ... LIMIT offset,rows ********* +show relaylog events in 'slave-relay-bin.000003' from limit 1, 3; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION +slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (1) +FLUSH LOGS; +FLUSH LOGS; +DROP TABLE t1; +[MASTER] ********* SOW BINLOG EVENTS IN ... ********* +show binlog events in 'master-bin.000002' from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Query # # use `test`; DROP TABLE t1 +[MASTER] ********* SOW BINLOG EVENTS ********* +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (5) +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (6) +master-bin.000001 # Rotate # # master-bin.000002;pos=4 +[SLAVE] ********* SOW BINLOG EVENTS IN ... ********* +show binlog events in 'slave-bin.000002' from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 # Query # # use `test`; DROP TABLE t1 +[SLAVE] ********* SOW BINLOG EVENTS ********* +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (4) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (5) +slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (6) +slave-bin.000001 # Rotate # # slave-bin.000002;pos=4 +[SLAVE] ********* SOW RELAYLOG EVENTS IN ... ********* +show relaylog events in 'slave-relay-bin.000005' from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000005 # Rotate # # slave-relay-bin.000006;pos=4 +[SLAVE] ********* SOW RELAYLOG EVENTS ********* +show relaylog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +slave-relay-bin.000005 # Rotate # # master-bin.000002;pos=4 +slave-relay-bin.000005 # Rotate # # slave-relay-bin.000006;pos=4 diff --git a/mysql-test/suite/rpl/t/rpl_row_show_relaylog_events.test b/mysql-test/suite/rpl/t/rpl_row_show_relaylog_events.test new file mode 100644 index 00000000000..6a426efc7ea --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_show_relaylog_events.test @@ -0,0 +1,18 @@ +# BUG#28777 SHOW BINLOG EVENTS does not work on relay log files +# +# GOAL +# ==== +# +# Test that SHOW BINLOG EVENTS and the new SHOW RELAYLOG EVENTS works after +# the patch, both on master and slave. +# +# HOW +# === +# +# This test issues SHOW [BINLOG|RELAYLOG] EVENTS both on master and slave after +# some statements have been issued. + +-- source include/master-slave.inc +-- source include/have_binlog_format_row.inc + +-- source extra/rpl_tests/rpl_show_relaylog_events.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_mix_show_relaylog_events.test b/mysql-test/suite/rpl/t/rpl_stm_mix_show_relaylog_events.test new file mode 100644 index 00000000000..523e883d9fa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_mix_show_relaylog_events.test @@ -0,0 +1,18 @@ +# BUG#28777 SHOW BINLOG EVENTS does not work on relay log files +# +# GOAL +# ==== +# +# Test that SHOW BINLOG EVENTS and the new SHOW RELAYLOG EVENTS works after +# the patch, both on master and slave. +# +# HOW +# === +# +# This test issues SHOW [BINLOG|RELAYLOG] EVENTS both on master and slave after +# some statements have been issued. + +-- source include/master-slave.inc +-- source include/have_binlog_format_mixed_or_statement.inc + +-- source extra/rpl_tests/rpl_show_relaylog_events.inc diff --git a/sql/lex.h b/sql/lex.h index b199a79350b..dd37d837045 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -429,6 +429,7 @@ static SYMBOL symbols[] = { { "REDUNDANT", SYM(REDUNDANT_SYM)}, { "REFERENCES", SYM(REFERENCES)}, { "REGEXP", SYM(REGEXP)}, + { "RELAYLOG", SYM(RELAYLOG_SYM)}, { "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM)}, { "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM)}, { "RELAY_THREAD", SYM(RELAY_THREAD)}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7e9eb6e7291..9b70096eb73 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3135,6 +3135,7 @@ SHOW_VAR com_status_vars[]= { {"show_processlist", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PROCESSLIST]), SHOW_LONG_STATUS}, {"show_profile", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PROFILE]), SHOW_LONG_STATUS}, {"show_profiles", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PROFILES]), SHOW_LONG_STATUS}, + {"show_relaylog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_RELAYLOG_EVENTS]), SHOW_LONG_STATUS}, {"show_slave_hosts", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_HOSTS]), SHOW_LONG_STATUS}, {"show_slave_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_STAT]), SHOW_LONG_STATUS}, {"show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 0736e5fc2a8..9fed5db6e3a 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -174,6 +174,7 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_SHOW_AUTHORS: case SQLCOM_SHOW_BINLOGS: case SQLCOM_SHOW_BINLOG_EVENTS: + case SQLCOM_SHOW_RELAYLOG_EVENTS: case SQLCOM_SHOW_CHARSETS: case SQLCOM_SHOW_COLLATIONS: case SQLCOM_SHOW_COLUMN_TYPES: diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6f9f667a75a..7db239cf9e3 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -121,7 +121,7 @@ enum enum_sql_command { SQLCOM_SHOW_CREATE_TRIGGER, SQLCOM_ALTER_DB_UPGRADE, SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, - + SQLCOM_SHOW_RELAYLOG_EVENTS, /* When a command is added here, be sure it's also added in mysqld.cc in "struct show_var_st status_vars[]= {" ... diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ca27d476213..513b9230c37 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2319,6 +2319,7 @@ mysql_execute_command(THD *thd) res = show_slave_hosts(thd); break; } + case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */ case SQLCOM_SHOW_BINLOG_EVENTS: { if (check_global_access(thd, REPL_SLAVE_ACL)) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 0ec8d91214c..4d9b7410b88 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1401,6 +1401,7 @@ bool mysql_show_binlog_events(THD* thd) bool ret = TRUE; IO_CACHE log; File file = -1; + MYSQL_BIN_LOG *binary_log= NULL; DBUG_ENTER("mysql_show_binlog_events"); Log_event::init_show_field_list(&field_list); @@ -1411,14 +1412,30 @@ bool mysql_show_binlog_events(THD* thd) Format_description_log_event *description_event= new Format_description_log_event(3); /* MySQL 4.0 by default */ - /* - Wait for handlers to insert any pending information - into the binlog. For e.g. ndb which updates the binlog asynchronously - this is needed so that the uses sees all its own commands in the binlog - */ - ha_binlog_wait(thd); + DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS || + thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS); - if (mysql_bin_log.is_open()) + /* select wich binary log to use: binlog or relay */ + if ( thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS ) + { + /* + Wait for handlers to insert any pending information + into the binlog. For e.g. ndb which updates the binlog asynchronously + this is needed so that the uses sees all its own commands in the binlog + */ + ha_binlog_wait(thd); + + binary_log= &mysql_bin_log; + } + else /* showing relay log contents */ + { + if (!active_mi) + DBUG_RETURN(TRUE); + + binary_log= &(active_mi->rli.relay_log); + } + + if (binary_log->is_open()) { LEX_MASTER_INFO *lex_mi= &thd->lex->mi; SELECT_LEX_UNIT *unit= &thd->lex->unit; @@ -1426,7 +1443,7 @@ bool mysql_show_binlog_events(THD* thd) my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly char search_file_name[FN_REFLEN], *name; const char *log_file_name = lex_mi->log_file_name; - pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock(); + pthread_mutex_t *log_lock = binary_log->get_log_lock(); LOG_INFO linfo; Log_event* ev; @@ -1436,13 +1453,13 @@ bool mysql_show_binlog_events(THD* thd) name= search_file_name; if (log_file_name) - mysql_bin_log.make_log_name(search_file_name, log_file_name); + binary_log->make_log_name(search_file_name, log_file_name); else name=0; // Find first log linfo.index_file_offset = 0; - if (mysql_bin_log.find_log_pos(&linfo, name, 1)) + if (binary_log->find_log_pos(&linfo, name, 1)) { errmsg = "Could not find target log"; goto err; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a18f57bf9cf..1b415fea52d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -930,6 +930,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token REDUNDANT_SYM %token REFERENCES /* SQL-2003-R */ %token REGEXP +%token RELAYLOG_SYM %token RELAY_LOG_FILE_SYM %token RELAY_LOG_POS_SYM %token RELAY_THREAD @@ -9947,6 +9948,11 @@ show_param: LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS; } opt_limit_clause_init + | RELAYLOG_SYM EVENTS_SYM binlog_in binlog_from + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS; + } opt_limit_clause_init | keys_or_index from_or_in table_ident opt_db where_clause { LEX *lex= Lex; @@ -11588,6 +11594,7 @@ keyword_sp: | REDO_BUFFER_SIZE_SYM {} | REDOFILE_SYM {} | REDUNDANT_SYM {} + | RELAYLOG_SYM {} | RELAY_LOG_FILE_SYM {} | RELAY_LOG_POS_SYM {} | RELAY_THREAD {} From d94e279c7ce6953f50f033278a385ab8633526ce Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 29 Sep 2009 00:13:56 +0100 Subject: [PATCH 022/274] Fixed tree_name: mysql-5.1 --> mysql-5.1-rep+2 --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index f044f8e62da..4e9e581f800 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.1" +tree_name = "mysql-5.1-rep+2" From 5983785ef4b04b865ea1d78c8d452642913a83f3 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Tue, 29 Sep 2009 14:16:23 +0300 Subject: [PATCH 023/274] WL#342 heartbeat backporting from 6.0 code base to 5.1. --- mysql-test/extra/binlog_tests/binlog.test | 4 +- .../mix_innodb_myisam_binlog.test | 4 +- mysql-test/extra/rpl_tests/rpl_loaddata.test | 6 +- mysql-test/extra/rpl_tests/rpl_log.test | 6 +- mysql-test/include/show_binlog_events.inc | 2 +- mysql-test/include/show_binlog_events2.inc | 2 +- mysql-test/r/sp_trans_log.result | 12 +- .../suite/binlog/r/binlog_innodb.result | 10 +- .../suite/binlog/r/binlog_row_binlog.result | 1617 +++++++++-------- .../suite/binlog/r/binlog_stm_binlog.result | 8 +- mysql-test/suite/binlog/t/binlog_innodb.test | 6 +- mysql-test/suite/binlog/t/binlog_killed.test | 2 +- .../binlog/t/binlog_killed_simulate.test | 4 +- .../suite/rpl/r/rpl_binlog_grant.result | 42 +- .../suite/rpl/r/rpl_deadlock_innodb.result | 2 +- .../suite/rpl/r/rpl_extraCol_innodb.result | 4 +- .../suite/rpl/r/rpl_extraCol_myisam.result | 4 +- .../rpl/r/rpl_known_bugs_detection.result | 4 +- mysql-test/suite/rpl/r/rpl_loaddata.result | 126 +- .../suite/rpl/r/rpl_loaddata_fatal.result | 8 +- mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result | 4 +- .../suite/rpl/r/rpl_row_basic_11bugs.result | 12 +- .../suite/rpl/r/rpl_row_conflicts.result | 4 +- .../suite/rpl/r/rpl_row_create_table.result | 138 +- mysql-test/suite/rpl/r/rpl_row_drop.result | 8 +- .../suite/rpl/r/rpl_row_flsh_tbls.result | 4 +- mysql-test/suite/rpl/r/rpl_row_log.result | 10 +- .../suite/rpl/r/rpl_row_log_innodb.result | 10 +- mysql-test/suite/rpl/r/rpl_slave_skip.result | 8 +- mysql-test/suite/rpl/r/rpl_sp.result | 178 +- .../suite/rpl/r/rpl_stm_flsh_tbls.result | 4 +- mysql-test/suite/rpl/r/rpl_stm_log.result | 10 +- mysql-test/suite/rpl/t/rpl_binlog_grant.test | 8 +- .../suite/rpl/t/rpl_row_create_table.test | 16 +- mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test | 2 +- .../suite/rpl/t/rpl_row_mysqlbinlog.test | 8 +- mysql-test/suite/rpl/t/rpl_sp.test | 4 +- mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test | 2 +- mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result | 10 +- .../suite/rpl_ndb/r/rpl_truncate_7ndb.result | 68 +- mysql-test/t/ctype_cp932_binlog_stm.test | 4 +- mysql-test/t/mysqlbinlog.test | 6 +- mysql-test/t/mysqlbinlog2.test | 20 +- mysql-test/t/sp_trans_log.test | 3 +- sql/lex.h | 1 + sql/log.cc | 53 +- sql/log.h | 5 +- sql/log_event.cc | 14 + sql/log_event.h | 57 + sql/mysqld.cc | 36 + sql/rpl_mi.cc | 39 +- sql/rpl_mi.h | 2 + sql/slave.cc | 141 +- sql/slave.h | 12 +- sql/sql_lex.h | 5 +- sql/sql_repl.cc | 190 +- sql/sql_yacc.yy | 49 +- 57 files changed, 1809 insertions(+), 1209 deletions(-) diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index 5d898d41a54..08510d661e2 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -43,10 +43,10 @@ commit; drop table t1; --replace_column 2 # 5 # --replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\// -show binlog events in 'master-bin.000001' from 106; +show binlog events in 'master-bin.000001' from 107; --replace_column 2 # 5 # --replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\// -show binlog events in 'master-bin.000002' from 106; +show binlog events in 'master-bin.000002' from 107; # 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 5db79e4f848..da0b77fbc23 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test @@ -323,12 +323,12 @@ let $MYSQLD_DATADIR= `select @@datadir`; # and does not make slave to stop) if (`select @@binlog_format = 'ROW'`) { - --exec $MYSQL_BINLOG --start-position=524 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output + --exec $MYSQL_BINLOG --start-position=525 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output } if (`select @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`) { - --exec $MYSQL_BINLOG --start-position=555 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output + --exec $MYSQL_BINLOG --start-position=556 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output } --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR diff --git a/mysql-test/extra/rpl_tests/rpl_loaddata.test b/mysql-test/extra/rpl_tests/rpl_loaddata.test index 26916642cae..129a39ac509 100644 --- a/mysql-test/extra/rpl_tests/rpl_loaddata.test +++ b/mysql-test/extra/rpl_tests/rpl_loaddata.test @@ -72,7 +72,7 @@ start slave; sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 8 # 9 # 16 # 23 # 33 # -show slave status; +--query_vertical show slave status; # Trigger error again to test CHANGE MASTER @@ -94,7 +94,7 @@ change master to master_user='test'; change master to master_user='root'; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 8 # 9 # 16 # 23 # 33 # -show slave status; +--query_vertical show slave status; # Trigger error again to test RESET SLAVE @@ -116,7 +116,7 @@ stop slave; reset slave; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 8 # 9 # 16 # 23 # 33 # -show slave status; +--query_vertical show slave status; # Finally, see if logging is done ok on master for a failing LOAD DATA INFILE diff --git a/mysql-test/extra/rpl_tests/rpl_log.test b/mysql-test/extra/rpl_tests/rpl_log.test index e4ebfd68761..0517fea1be3 100644 --- a/mysql-test/extra/rpl_tests/rpl_log.test +++ b/mysql-test/extra/rpl_tests/rpl_log.test @@ -37,13 +37,13 @@ select count(*) from t1; show binlog events; --replace_column 2 # 5 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ -show binlog events from 106 limit 1; +show binlog events from 107 limit 1; --replace_column 2 # 5 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ -show binlog events from 106 limit 2; +show binlog events from 107 limit 2; --replace_column 2 # 5 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ -show binlog events from 106 limit 2,1; +show binlog events from 107 limit 2,1; flush logs; # We need an extra update before doing save_master_pos. diff --git a/mysql-test/include/show_binlog_events.inc b/mysql-test/include/show_binlog_events.inc index 68f913a16a3..93014d9f1a3 100644 --- a/mysql-test/include/show_binlog_events.inc +++ b/mysql-test/include/show_binlog_events.inc @@ -2,7 +2,7 @@ if (!$binlog_start) { - let $binlog_start=106; + let $binlog_start=107; } --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $binlog_start --replace_column 2 # 4 # 5 # diff --git a/mysql-test/include/show_binlog_events2.inc b/mysql-test/include/show_binlog_events2.inc index 5dd272c562d..0e1a889bacc 100644 --- a/mysql-test/include/show_binlog_events2.inc +++ b/mysql-test/include/show_binlog_events2.inc @@ -1,4 +1,4 @@ ---let $binlog_start=106 +--let $binlog_start=107 --replace_result $binlog_start --replace_column 2 # 5 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ diff --git a/mysql-test/r/sp_trans_log.result b/mysql-test/r/sp_trans_log.result index 7a6173b89e2..3eec6f70063 100644 --- a/mysql-test/r/sp_trans_log.result +++ b/mysql-test/r/sp_trans_log.result @@ -14,13 +14,13 @@ end| reset master| insert into t2 values (bug23333(),1)| ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -show binlog events from 106 /* with fixes for #23333 will show there is the query */| +show binlog events from | Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # # -master-bin.000001 # Table_map 1 # # -master-bin.000001 # Table_map 1 # # -master-bin.000001 # Write_rows 1 # # -master-bin.000001 # Query 1 # # +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*),@a from t1 /* must be 1,1 */| count(*) @a 1 1 diff --git a/mysql-test/suite/binlog/r/binlog_innodb.result b/mysql-test/suite/binlog/r/binlog_innodb.result index 1922897f631..424f7d60829 100644 --- a/mysql-test/suite/binlog/r/binlog_innodb.result +++ b/mysql-test/suite/binlog/r/binlog_innodb.result @@ -156,9 +156,10 @@ select * from t2 /* must be (3,1), (4,4) */; a b 1 1 4 4 -show master status /* there must no UPDATE in binlog */; +there must no UPDATE in binlog +show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 106 +master-bin.000001 # delete from t1; delete from t2; insert into t1 values (1,2),(3,4),(4,4); @@ -166,8 +167,9 @@ insert into t2 values (1,2),(3,4),(4,4); reset master; UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; ERROR 23000: Duplicate entry '4' for key 'PRIMARY' -show master status /* there must be no UPDATE query event */; +there must no UPDATE in binlog +show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 106 +master-bin.000001 # drop table t1, t2; End of tests diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index f6b5392dbc8..d2d702b12a0 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -26,7 +26,7 @@ create table t1 (n int) engine=innodb; begin; commit; drop table t1; -show binlog events in 'master-bin.000001' from 106; +show binlog events in 'master-bin.000001' from 107; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1 (n int) engine=innodb master-bin.000001 # Query 1 # BEGIN @@ -232,7 +232,7 @@ master-bin.000001 # Table_map 1 # table_id: # (test.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Xid 1 # COMMIT /* xid= */ master-bin.000001 # Rotate 1 # master-bin.000002;pos=4 -show binlog events in 'master-bin.000002' from 106; +show binlog events in 'master-bin.000002' from 107; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000002 # Query 1 # use `test`; drop table t1 set @ac = @@autocommit; @@ -273,802 +273,819 @@ master-bin.000001 349 Table_map 1 390 table_id: # (test.t1) master-bin.000001 390 Write_rows 1 424 table_id: # flags: STMT_END_F master-bin.000001 424 Table_map 1 465 table_id: # (test.t1) master-bin.000001 465 Write_rows 1 499 table_id: # flags: STMT_END_F -master-bin.000001 499 Table_map 1 540 table_id: # (test.t1) -master-bin.000001 540 Write_rows 1 574 table_id: # flags: STMT_END_F -master-bin.000001 574 Table_map 1 615 table_id: # (test.t1) -master-bin.000001 615 Write_rows 1 649 table_id: # flags: STMT_END_F -master-bin.000001 649 Table_map 1 690 table_id: # (test.t1) -master-bin.000001 690 Write_rows 1 724 table_id: # flags: STMT_END_F -master-bin.000001 724 Table_map 1 765 table_id: # (test.t1) -master-bin.000001 765 Write_rows 1 799 table_id: # flags: STMT_END_F -master-bin.000001 799 Table_map 1 840 table_id: # (test.t1) -master-bin.000001 840 Write_rows 1 874 table_id: # flags: STMT_END_F -master-bin.000001 874 Table_map 1 915 table_id: # (test.t1) -master-bin.000001 915 Write_rows 1 949 table_id: # flags: STMT_END_F -master-bin.000001 949 Table_map 1 990 table_id: # (test.t1) -master-bin.000001 990 Write_rows 1 1024 table_id: # flags: STMT_END_F -master-bin.000001 1024 Table_map 1 1065 table_id: # (test.t1) -master-bin.000001 1065 Write_rows 1 1099 table_id: # flags: STMT_END_F -master-bin.000001 1099 Table_map 1 1140 table_id: # (test.t1) -master-bin.000001 1140 Write_rows 1 1174 table_id: # flags: STMT_END_F -master-bin.000001 1174 Table_map 1 1215 table_id: # (test.t1) -master-bin.000001 1215 Write_rows 1 1249 table_id: # flags: STMT_END_F -master-bin.000001 1249 Table_map 1 1290 table_id: # (test.t1) -master-bin.000001 1290 Write_rows 1 1324 table_id: # flags: STMT_END_F -master-bin.000001 1324 Table_map 1 1365 table_id: # (test.t1) -master-bin.000001 1365 Write_rows 1 1399 table_id: # flags: STMT_END_F -master-bin.000001 1399 Table_map 1 1440 table_id: # (test.t1) -master-bin.000001 1440 Write_rows 1 1474 table_id: # flags: STMT_END_F -master-bin.000001 1474 Table_map 1 1515 table_id: # (test.t1) -master-bin.000001 1515 Write_rows 1 1549 table_id: # flags: STMT_END_F -master-bin.000001 1549 Table_map 1 1590 table_id: # (test.t1) -master-bin.000001 1590 Write_rows 1 1624 table_id: # flags: STMT_END_F -master-bin.000001 1624 Table_map 1 1665 table_id: # (test.t1) -master-bin.000001 1665 Write_rows 1 1699 table_id: # flags: STMT_END_F -master-bin.000001 1699 Table_map 1 1740 table_id: # (test.t1) -master-bin.000001 1740 Write_rows 1 1774 table_id: # flags: STMT_END_F -master-bin.000001 1774 Table_map 1 1815 table_id: # (test.t1) -master-bin.000001 1815 Write_rows 1 1849 table_id: # flags: STMT_END_F -master-bin.000001 1849 Table_map 1 1890 table_id: # (test.t1) -master-bin.000001 1890 Write_rows 1 1924 table_id: # flags: STMT_END_F -master-bin.000001 1924 Table_map 1 1965 table_id: # (test.t1) -master-bin.000001 1965 Write_rows 1 1999 table_id: # flags: STMT_END_F -master-bin.000001 1999 Table_map 1 2040 table_id: # (test.t1) -master-bin.000001 2040 Write_rows 1 2074 table_id: # flags: STMT_END_F -master-bin.000001 2074 Table_map 1 2115 table_id: # (test.t1) -master-bin.000001 2115 Write_rows 1 2149 table_id: # flags: STMT_END_F -master-bin.000001 2149 Table_map 1 2190 table_id: # (test.t1) -master-bin.000001 2190 Write_rows 1 2224 table_id: # flags: STMT_END_F -master-bin.000001 2224 Table_map 1 2265 table_id: # (test.t1) -master-bin.000001 2265 Write_rows 1 2299 table_id: # flags: STMT_END_F -master-bin.000001 2299 Table_map 1 2340 table_id: # (test.t1) -master-bin.000001 2340 Write_rows 1 2374 table_id: # flags: STMT_END_F -master-bin.000001 2374 Table_map 1 2415 table_id: # (test.t1) -master-bin.000001 2415 Write_rows 1 2449 table_id: # flags: STMT_END_F -master-bin.000001 2449 Table_map 1 2490 table_id: # (test.t1) -master-bin.000001 2490 Write_rows 1 2524 table_id: # flags: STMT_END_F -master-bin.000001 2524 Table_map 1 2565 table_id: # (test.t1) -master-bin.000001 2565 Write_rows 1 2599 table_id: # flags: STMT_END_F -master-bin.000001 2599 Table_map 1 2640 table_id: # (test.t1) -master-bin.000001 2640 Write_rows 1 2674 table_id: # flags: STMT_END_F -master-bin.000001 2674 Table_map 1 2715 table_id: # (test.t1) -master-bin.000001 2715 Write_rows 1 2749 table_id: # flags: STMT_END_F -master-bin.000001 2749 Table_map 1 2790 table_id: # (test.t1) -master-bin.000001 2790 Write_rows 1 2824 table_id: # flags: STMT_END_F -master-bin.000001 2824 Table_map 1 2865 table_id: # (test.t1) -master-bin.000001 2865 Write_rows 1 2899 table_id: # flags: STMT_END_F -master-bin.000001 2899 Table_map 1 2940 table_id: # (test.t1) -master-bin.000001 2940 Write_rows 1 2974 table_id: # flags: STMT_END_F -master-bin.000001 2974 Table_map 1 3015 table_id: # (test.t1) -master-bin.000001 3015 Write_rows 1 3049 table_id: # flags: STMT_END_F -master-bin.000001 3049 Table_map 1 3090 table_id: # (test.t1) -master-bin.000001 3090 Write_rows 1 3124 table_id: # flags: STMT_END_F -master-bin.000001 3124 Table_map 1 3165 table_id: # (test.t1) -master-bin.000001 3165 Write_rows 1 3199 table_id: # flags: STMT_END_F -master-bin.000001 3199 Table_map 1 3240 table_id: # (test.t1) -master-bin.000001 3240 Write_rows 1 3274 table_id: # flags: STMT_END_F -master-bin.000001 3274 Table_map 1 3315 table_id: # (test.t1) -master-bin.000001 3315 Write_rows 1 3349 table_id: # flags: STMT_END_F -master-bin.000001 3349 Table_map 1 3390 table_id: # (test.t1) -master-bin.000001 3390 Write_rows 1 3424 table_id: # flags: STMT_END_F -master-bin.000001 3424 Table_map 1 3465 table_id: # (test.t1) -master-bin.000001 3465 Write_rows 1 3499 table_id: # flags: STMT_END_F -master-bin.000001 3499 Table_map 1 3540 table_id: # (test.t1) -master-bin.000001 3540 Write_rows 1 3574 table_id: # flags: STMT_END_F -master-bin.000001 3574 Table_map 1 3615 table_id: # (test.t1) -master-bin.000001 3615 Write_rows 1 3649 table_id: # flags: STMT_END_F -master-bin.000001 3649 Table_map 1 3690 table_id: # (test.t1) -master-bin.000001 3690 Write_rows 1 3724 table_id: # flags: STMT_END_F -master-bin.000001 3724 Table_map 1 3765 table_id: # (test.t1) -master-bin.000001 3765 Write_rows 1 3799 table_id: # flags: STMT_END_F -master-bin.000001 3799 Table_map 1 3840 table_id: # (test.t1) -master-bin.000001 3840 Write_rows 1 3874 table_id: # flags: STMT_END_F -master-bin.000001 3874 Table_map 1 3915 table_id: # (test.t1) -master-bin.000001 3915 Write_rows 1 3949 table_id: # flags: STMT_END_F -master-bin.000001 3949 Table_map 1 3990 table_id: # (test.t1) -master-bin.000001 3990 Write_rows 1 4024 table_id: # flags: STMT_END_F -master-bin.000001 4024 Table_map 1 4065 table_id: # (test.t1) -master-bin.000001 4065 Write_rows 1 4099 table_id: # flags: STMT_END_F -master-bin.000001 4099 Table_map 1 4140 table_id: # (test.t1) -master-bin.000001 4140 Write_rows 1 4174 table_id: # flags: STMT_END_F -master-bin.000001 4174 Table_map 1 4215 table_id: # (test.t1) -master-bin.000001 4215 Write_rows 1 4249 table_id: # flags: STMT_END_F -master-bin.000001 4249 Table_map 1 4290 table_id: # (test.t1) -master-bin.000001 4290 Write_rows 1 4324 table_id: # flags: STMT_END_F -master-bin.000001 4324 Table_map 1 4365 table_id: # (test.t1) -master-bin.000001 4365 Write_rows 1 4399 table_id: # flags: STMT_END_F -master-bin.000001 4399 Table_map 1 4440 table_id: # (test.t1) -master-bin.000001 4440 Write_rows 1 4474 table_id: # flags: STMT_END_F -master-bin.000001 4474 Table_map 1 4515 table_id: # (test.t1) -master-bin.000001 4515 Write_rows 1 4549 table_id: # flags: STMT_END_F -master-bin.000001 4549 Table_map 1 4590 table_id: # (test.t1) -master-bin.000001 4590 Write_rows 1 4624 table_id: # flags: STMT_END_F -master-bin.000001 4624 Table_map 1 4665 table_id: # (test.t1) -master-bin.000001 4665 Write_rows 1 4699 table_id: # flags: STMT_END_F -master-bin.000001 4699 Table_map 1 4740 table_id: # (test.t1) -master-bin.000001 4740 Write_rows 1 4774 table_id: # flags: STMT_END_F -master-bin.000001 4774 Table_map 1 4815 table_id: # (test.t1) -master-bin.000001 4815 Write_rows 1 4849 table_id: # flags: STMT_END_F -master-bin.000001 4849 Table_map 1 4890 table_id: # (test.t1) -master-bin.000001 4890 Write_rows 1 4924 table_id: # flags: STMT_END_F -master-bin.000001 4924 Table_map 1 4965 table_id: # (test.t1) -master-bin.000001 4965 Write_rows 1 4999 table_id: # flags: STMT_END_F -master-bin.000001 4999 Table_map 1 5040 table_id: # (test.t1) -master-bin.000001 5040 Write_rows 1 5074 table_id: # flags: STMT_END_F -master-bin.000001 5074 Table_map 1 5115 table_id: # (test.t1) -master-bin.000001 5115 Write_rows 1 5149 table_id: # flags: STMT_END_F -master-bin.000001 5149 Table_map 1 5190 table_id: # (test.t1) -master-bin.000001 5190 Write_rows 1 5224 table_id: # flags: STMT_END_F -master-bin.000001 5224 Table_map 1 5265 table_id: # (test.t1) -master-bin.000001 5265 Write_rows 1 5299 table_id: # flags: STMT_END_F -master-bin.000001 5299 Table_map 1 5340 table_id: # (test.t1) -master-bin.000001 5340 Write_rows 1 5374 table_id: # flags: STMT_END_F -master-bin.000001 5374 Table_map 1 5415 table_id: # (test.t1) -master-bin.000001 5415 Write_rows 1 5449 table_id: # flags: STMT_END_F -master-bin.000001 5449 Table_map 1 5490 table_id: # (test.t1) -master-bin.000001 5490 Write_rows 1 5524 table_id: # flags: STMT_END_F -master-bin.000001 5524 Table_map 1 5565 table_id: # (test.t1) -master-bin.000001 5565 Write_rows 1 5599 table_id: # flags: STMT_END_F -master-bin.000001 5599 Table_map 1 5640 table_id: # (test.t1) -master-bin.000001 5640 Write_rows 1 5674 table_id: # flags: STMT_END_F -master-bin.000001 5674 Table_map 1 5715 table_id: # (test.t1) -master-bin.000001 5715 Write_rows 1 5749 table_id: # flags: STMT_END_F -master-bin.000001 5749 Table_map 1 5790 table_id: # (test.t1) -master-bin.000001 5790 Write_rows 1 5824 table_id: # flags: STMT_END_F -master-bin.000001 5824 Table_map 1 5865 table_id: # (test.t1) -master-bin.000001 5865 Write_rows 1 5899 table_id: # flags: STMT_END_F -master-bin.000001 5899 Table_map 1 5940 table_id: # (test.t1) -master-bin.000001 5940 Write_rows 1 5974 table_id: # flags: STMT_END_F -master-bin.000001 5974 Table_map 1 6015 table_id: # (test.t1) -master-bin.000001 6015 Write_rows 1 6049 table_id: # flags: STMT_END_F -master-bin.000001 6049 Table_map 1 6090 table_id: # (test.t1) -master-bin.000001 6090 Write_rows 1 6124 table_id: # flags: STMT_END_F -master-bin.000001 6124 Table_map 1 6165 table_id: # (test.t1) -master-bin.000001 6165 Write_rows 1 6199 table_id: # flags: STMT_END_F -master-bin.000001 6199 Table_map 1 6240 table_id: # (test.t1) -master-bin.000001 6240 Write_rows 1 6274 table_id: # flags: STMT_END_F -master-bin.000001 6274 Table_map 1 6315 table_id: # (test.t1) -master-bin.000001 6315 Write_rows 1 6349 table_id: # flags: STMT_END_F -master-bin.000001 6349 Table_map 1 6390 table_id: # (test.t1) -master-bin.000001 6390 Write_rows 1 6424 table_id: # flags: STMT_END_F -master-bin.000001 6424 Table_map 1 6465 table_id: # (test.t1) -master-bin.000001 6465 Write_rows 1 6499 table_id: # flags: STMT_END_F -master-bin.000001 6499 Table_map 1 6540 table_id: # (test.t1) -master-bin.000001 6540 Write_rows 1 6574 table_id: # flags: STMT_END_F -master-bin.000001 6574 Table_map 1 6615 table_id: # (test.t1) -master-bin.000001 6615 Write_rows 1 6649 table_id: # flags: STMT_END_F -master-bin.000001 6649 Table_map 1 6690 table_id: # (test.t1) -master-bin.000001 6690 Write_rows 1 6724 table_id: # flags: STMT_END_F -master-bin.000001 6724 Table_map 1 6765 table_id: # (test.t1) -master-bin.000001 6765 Write_rows 1 6799 table_id: # flags: STMT_END_F -master-bin.000001 6799 Table_map 1 6840 table_id: # (test.t1) -master-bin.000001 6840 Write_rows 1 6874 table_id: # flags: STMT_END_F -master-bin.000001 6874 Table_map 1 6915 table_id: # (test.t1) -master-bin.000001 6915 Write_rows 1 6949 table_id: # flags: STMT_END_F -master-bin.000001 6949 Table_map 1 6990 table_id: # (test.t1) -master-bin.000001 6990 Write_rows 1 7024 table_id: # flags: STMT_END_F -master-bin.000001 7024 Table_map 1 7065 table_id: # (test.t1) -master-bin.000001 7065 Write_rows 1 7099 table_id: # flags: STMT_END_F -master-bin.000001 7099 Table_map 1 7140 table_id: # (test.t1) -master-bin.000001 7140 Write_rows 1 7174 table_id: # flags: STMT_END_F -master-bin.000001 7174 Table_map 1 7215 table_id: # (test.t1) -master-bin.000001 7215 Write_rows 1 7249 table_id: # flags: STMT_END_F -master-bin.000001 7249 Table_map 1 7290 table_id: # (test.t1) -master-bin.000001 7290 Write_rows 1 7324 table_id: # flags: STMT_END_F -master-bin.000001 7324 Table_map 1 7365 table_id: # (test.t1) -master-bin.000001 7365 Write_rows 1 7399 table_id: # flags: STMT_END_F -master-bin.000001 7399 Table_map 1 7440 table_id: # (test.t1) -master-bin.000001 7440 Write_rows 1 7474 table_id: # flags: STMT_END_F -master-bin.000001 7474 Table_map 1 7515 table_id: # (test.t1) -master-bin.000001 7515 Write_rows 1 7549 table_id: # flags: STMT_END_F -master-bin.000001 7549 Table_map 1 7590 table_id: # (test.t1) -master-bin.000001 7590 Write_rows 1 7624 table_id: # flags: STMT_END_F -master-bin.000001 7624 Table_map 1 7665 table_id: # (test.t1) -master-bin.000001 7665 Write_rows 1 7699 table_id: # flags: STMT_END_F -master-bin.000001 7699 Table_map 1 7740 table_id: # (test.t1) -master-bin.000001 7740 Write_rows 1 7774 table_id: # flags: STMT_END_F -master-bin.000001 7774 Table_map 1 7815 table_id: # (test.t1) -master-bin.000001 7815 Write_rows 1 7849 table_id: # flags: STMT_END_F -master-bin.000001 7849 Table_map 1 7890 table_id: # (test.t1) -master-bin.000001 7890 Write_rows 1 7924 table_id: # flags: STMT_END_F -master-bin.000001 7924 Table_map 1 7965 table_id: # (test.t1) -master-bin.000001 7965 Write_rows 1 7999 table_id: # flags: STMT_END_F -master-bin.000001 7999 Table_map 1 8040 table_id: # (test.t1) -master-bin.000001 8040 Write_rows 1 8074 table_id: # flags: STMT_END_F -master-bin.000001 8074 Table_map 1 8115 table_id: # (test.t1) -master-bin.000001 8115 Write_rows 1 8149 table_id: # flags: STMT_END_F -master-bin.000001 8149 Table_map 1 8190 table_id: # (test.t1) -master-bin.000001 8190 Write_rows 1 8224 table_id: # flags: STMT_END_F -master-bin.000001 8224 Table_map 1 8265 table_id: # (test.t1) -master-bin.000001 8265 Write_rows 1 8299 table_id: # flags: STMT_END_F -master-bin.000001 8299 Table_map 1 8340 table_id: # (test.t1) -master-bin.000001 8340 Write_rows 1 8374 table_id: # flags: STMT_END_F -master-bin.000001 8374 Table_map 1 8415 table_id: # (test.t1) -master-bin.000001 8415 Write_rows 1 8449 table_id: # flags: STMT_END_F -master-bin.000001 8449 Table_map 1 8490 table_id: # (test.t1) -master-bin.000001 8490 Write_rows 1 8524 table_id: # flags: STMT_END_F -master-bin.000001 8524 Table_map 1 8565 table_id: # (test.t1) -master-bin.000001 8565 Write_rows 1 8599 table_id: # flags: STMT_END_F -master-bin.000001 8599 Table_map 1 8640 table_id: # (test.t1) -master-bin.000001 8640 Write_rows 1 8674 table_id: # flags: STMT_END_F -master-bin.000001 8674 Table_map 1 8715 table_id: # (test.t1) -master-bin.000001 8715 Write_rows 1 8749 table_id: # flags: STMT_END_F -master-bin.000001 8749 Table_map 1 8790 table_id: # (test.t1) -master-bin.000001 8790 Write_rows 1 8824 table_id: # flags: STMT_END_F -master-bin.000001 8824 Table_map 1 8865 table_id: # (test.t1) -master-bin.000001 8865 Write_rows 1 8899 table_id: # flags: STMT_END_F -master-bin.000001 8899 Table_map 1 8940 table_id: # (test.t1) -master-bin.000001 8940 Write_rows 1 8974 table_id: # flags: STMT_END_F -master-bin.000001 8974 Table_map 1 9015 table_id: # (test.t1) -master-bin.000001 9015 Write_rows 1 9049 table_id: # flags: STMT_END_F -master-bin.000001 9049 Table_map 1 9090 table_id: # (test.t1) -master-bin.000001 9090 Write_rows 1 9124 table_id: # flags: STMT_END_F -master-bin.000001 9124 Table_map 1 9165 table_id: # (test.t1) -master-bin.000001 9165 Write_rows 1 9199 table_id: # flags: STMT_END_F -master-bin.000001 9199 Table_map 1 9240 table_id: # (test.t1) -master-bin.000001 9240 Write_rows 1 9274 table_id: # flags: STMT_END_F -master-bin.000001 9274 Table_map 1 9315 table_id: # (test.t1) -master-bin.000001 9315 Write_rows 1 9349 table_id: # flags: STMT_END_F -master-bin.000001 9349 Table_map 1 9390 table_id: # (test.t1) -master-bin.000001 9390 Write_rows 1 9424 table_id: # flags: STMT_END_F -master-bin.000001 9424 Table_map 1 9465 table_id: # (test.t1) -master-bin.000001 9465 Write_rows 1 9499 table_id: # flags: STMT_END_F -master-bin.000001 9499 Table_map 1 9540 table_id: # (test.t1) -master-bin.000001 9540 Write_rows 1 9574 table_id: # flags: STMT_END_F -master-bin.000001 9574 Table_map 1 9615 table_id: # (test.t1) -master-bin.000001 9615 Write_rows 1 9649 table_id: # flags: STMT_END_F -master-bin.000001 9649 Table_map 1 9690 table_id: # (test.t1) -master-bin.000001 9690 Write_rows 1 9724 table_id: # flags: STMT_END_F -master-bin.000001 9724 Table_map 1 9765 table_id: # (test.t1) -master-bin.000001 9765 Write_rows 1 9799 table_id: # flags: STMT_END_F -master-bin.000001 9799 Table_map 1 9840 table_id: # (test.t1) -master-bin.000001 9840 Write_rows 1 9874 table_id: # flags: STMT_END_F -master-bin.000001 9874 Table_map 1 9915 table_id: # (test.t1) -master-bin.000001 9915 Write_rows 1 9949 table_id: # flags: STMT_END_F -master-bin.000001 9949 Table_map 1 9990 table_id: # (test.t1) -master-bin.000001 9990 Write_rows 1 10024 table_id: # flags: STMT_END_F -master-bin.000001 10024 Table_map 1 10065 table_id: # (test.t1) -master-bin.000001 10065 Write_rows 1 10099 table_id: # flags: STMT_END_F -master-bin.000001 10099 Table_map 1 10140 table_id: # (test.t1) -master-bin.000001 10140 Write_rows 1 10174 table_id: # flags: STMT_END_F -master-bin.000001 10174 Table_map 1 10215 table_id: # (test.t1) -master-bin.000001 10215 Write_rows 1 10249 table_id: # flags: STMT_END_F -master-bin.000001 10249 Table_map 1 10290 table_id: # (test.t1) -master-bin.000001 10290 Write_rows 1 10324 table_id: # flags: STMT_END_F -master-bin.000001 10324 Table_map 1 10365 table_id: # (test.t1) -master-bin.000001 10365 Write_rows 1 10399 table_id: # flags: STMT_END_F -master-bin.000001 10399 Table_map 1 10440 table_id: # (test.t1) -master-bin.000001 10440 Write_rows 1 10474 table_id: # flags: STMT_END_F -master-bin.000001 10474 Table_map 1 10515 table_id: # (test.t1) -master-bin.000001 10515 Write_rows 1 10549 table_id: # flags: STMT_END_F -master-bin.000001 10549 Table_map 1 10590 table_id: # (test.t1) -master-bin.000001 10590 Write_rows 1 10624 table_id: # flags: STMT_END_F -master-bin.000001 10624 Table_map 1 10665 table_id: # (test.t1) -master-bin.000001 10665 Write_rows 1 10699 table_id: # flags: STMT_END_F -master-bin.000001 10699 Table_map 1 10740 table_id: # (test.t1) -master-bin.000001 10740 Write_rows 1 10774 table_id: # flags: STMT_END_F -master-bin.000001 10774 Table_map 1 10815 table_id: # (test.t1) -master-bin.000001 10815 Write_rows 1 10849 table_id: # flags: STMT_END_F -master-bin.000001 10849 Table_map 1 10890 table_id: # (test.t1) -master-bin.000001 10890 Write_rows 1 10924 table_id: # flags: STMT_END_F -master-bin.000001 10924 Table_map 1 10965 table_id: # (test.t1) -master-bin.000001 10965 Write_rows 1 10999 table_id: # flags: STMT_END_F -master-bin.000001 10999 Table_map 1 11040 table_id: # (test.t1) -master-bin.000001 11040 Write_rows 1 11074 table_id: # flags: STMT_END_F -master-bin.000001 11074 Table_map 1 11115 table_id: # (test.t1) -master-bin.000001 11115 Write_rows 1 11149 table_id: # flags: STMT_END_F -master-bin.000001 11149 Table_map 1 11190 table_id: # (test.t1) -master-bin.000001 11190 Write_rows 1 11224 table_id: # flags: STMT_END_F -master-bin.000001 11224 Table_map 1 11265 table_id: # (test.t1) -master-bin.000001 11265 Write_rows 1 11299 table_id: # flags: STMT_END_F -master-bin.000001 11299 Table_map 1 11340 table_id: # (test.t1) -master-bin.000001 11340 Write_rows 1 11374 table_id: # flags: STMT_END_F -master-bin.000001 11374 Table_map 1 11415 table_id: # (test.t1) -master-bin.000001 11415 Write_rows 1 11449 table_id: # flags: STMT_END_F -master-bin.000001 11449 Table_map 1 11490 table_id: # (test.t1) -master-bin.000001 11490 Write_rows 1 11524 table_id: # flags: STMT_END_F -master-bin.000001 11524 Table_map 1 11565 table_id: # (test.t1) -master-bin.000001 11565 Write_rows 1 11599 table_id: # flags: STMT_END_F -master-bin.000001 11599 Table_map 1 11640 table_id: # (test.t1) -master-bin.000001 11640 Write_rows 1 11674 table_id: # flags: STMT_END_F -master-bin.000001 11674 Table_map 1 11715 table_id: # (test.t1) -master-bin.000001 11715 Write_rows 1 11749 table_id: # flags: STMT_END_F -master-bin.000001 11749 Table_map 1 11790 table_id: # (test.t1) -master-bin.000001 11790 Write_rows 1 11824 table_id: # flags: STMT_END_F -master-bin.000001 11824 Table_map 1 11865 table_id: # (test.t1) -master-bin.000001 11865 Write_rows 1 11899 table_id: # flags: STMT_END_F -master-bin.000001 11899 Table_map 1 11940 table_id: # (test.t1) -master-bin.000001 11940 Write_rows 1 11974 table_id: # flags: STMT_END_F -master-bin.000001 11974 Table_map 1 12015 table_id: # (test.t1) -master-bin.000001 12015 Write_rows 1 12049 table_id: # flags: STMT_END_F -master-bin.000001 12049 Table_map 1 12090 table_id: # (test.t1) -master-bin.000001 12090 Write_rows 1 12124 table_id: # flags: STMT_END_F -master-bin.000001 12124 Table_map 1 12165 table_id: # (test.t1) -master-bin.000001 12165 Write_rows 1 12199 table_id: # flags: STMT_END_F -master-bin.000001 12199 Table_map 1 12240 table_id: # (test.t1) -master-bin.000001 12240 Write_rows 1 12274 table_id: # flags: STMT_END_F -master-bin.000001 12274 Table_map 1 12315 table_id: # (test.t1) -master-bin.000001 12315 Write_rows 1 12349 table_id: # flags: STMT_END_F -master-bin.000001 12349 Table_map 1 12390 table_id: # (test.t1) -master-bin.000001 12390 Write_rows 1 12424 table_id: # flags: STMT_END_F -master-bin.000001 12424 Table_map 1 12465 table_id: # (test.t1) -master-bin.000001 12465 Write_rows 1 12499 table_id: # flags: STMT_END_F -master-bin.000001 12499 Table_map 1 12540 table_id: # (test.t1) -master-bin.000001 12540 Write_rows 1 12574 table_id: # flags: STMT_END_F -master-bin.000001 12574 Table_map 1 12615 table_id: # (test.t1) -master-bin.000001 12615 Write_rows 1 12649 table_id: # flags: STMT_END_F -master-bin.000001 12649 Table_map 1 12690 table_id: # (test.t1) -master-bin.000001 12690 Write_rows 1 12724 table_id: # flags: STMT_END_F -master-bin.000001 12724 Table_map 1 12765 table_id: # (test.t1) -master-bin.000001 12765 Write_rows 1 12799 table_id: # flags: STMT_END_F -master-bin.000001 12799 Table_map 1 12840 table_id: # (test.t1) -master-bin.000001 12840 Write_rows 1 12874 table_id: # flags: STMT_END_F -master-bin.000001 12874 Table_map 1 12915 table_id: # (test.t1) -master-bin.000001 12915 Write_rows 1 12949 table_id: # flags: STMT_END_F -master-bin.000001 12949 Table_map 1 12990 table_id: # (test.t1) -master-bin.000001 12990 Write_rows 1 13024 table_id: # flags: STMT_END_F -master-bin.000001 13024 Table_map 1 13065 table_id: # (test.t1) -master-bin.000001 13065 Write_rows 1 13099 table_id: # flags: STMT_END_F -master-bin.000001 13099 Table_map 1 13140 table_id: # (test.t1) -master-bin.000001 13140 Write_rows 1 13174 table_id: # flags: STMT_END_F -master-bin.000001 13174 Table_map 1 13215 table_id: # (test.t1) -master-bin.000001 13215 Write_rows 1 13249 table_id: # flags: STMT_END_F -master-bin.000001 13249 Table_map 1 13290 table_id: # (test.t1) -master-bin.000001 13290 Write_rows 1 13324 table_id: # flags: STMT_END_F -master-bin.000001 13324 Table_map 1 13365 table_id: # (test.t1) -master-bin.000001 13365 Write_rows 1 13399 table_id: # flags: STMT_END_F -master-bin.000001 13399 Table_map 1 13440 table_id: # (test.t1) -master-bin.000001 13440 Write_rows 1 13474 table_id: # flags: STMT_END_F -master-bin.000001 13474 Table_map 1 13515 table_id: # (test.t1) -master-bin.000001 13515 Write_rows 1 13549 table_id: # flags: STMT_END_F -master-bin.000001 13549 Table_map 1 13590 table_id: # (test.t1) -master-bin.000001 13590 Write_rows 1 13624 table_id: # flags: STMT_END_F -master-bin.000001 13624 Table_map 1 13665 table_id: # (test.t1) -master-bin.000001 13665 Write_rows 1 13699 table_id: # flags: STMT_END_F -master-bin.000001 13699 Table_map 1 13740 table_id: # (test.t1) -master-bin.000001 13740 Write_rows 1 13774 table_id: # flags: STMT_END_F -master-bin.000001 13774 Table_map 1 13815 table_id: # (test.t1) -master-bin.000001 13815 Write_rows 1 13849 table_id: # flags: STMT_END_F -master-bin.000001 13849 Table_map 1 13890 table_id: # (test.t1) -master-bin.000001 13890 Write_rows 1 13924 table_id: # flags: STMT_END_F -master-bin.000001 13924 Table_map 1 13965 table_id: # (test.t1) -master-bin.000001 13965 Write_rows 1 13999 table_id: # flags: STMT_END_F -master-bin.000001 13999 Table_map 1 14040 table_id: # (test.t1) -master-bin.000001 14040 Write_rows 1 14074 table_id: # flags: STMT_END_F -master-bin.000001 14074 Table_map 1 14115 table_id: # (test.t1) -master-bin.000001 14115 Write_rows 1 14149 table_id: # flags: STMT_END_F -master-bin.000001 14149 Table_map 1 14190 table_id: # (test.t1) -master-bin.000001 14190 Write_rows 1 14224 table_id: # flags: STMT_END_F -master-bin.000001 14224 Table_map 1 14265 table_id: # (test.t1) -master-bin.000001 14265 Write_rows 1 14299 table_id: # flags: STMT_END_F -master-bin.000001 14299 Table_map 1 14340 table_id: # (test.t1) -master-bin.000001 14340 Write_rows 1 14374 table_id: # flags: STMT_END_F -master-bin.000001 14374 Table_map 1 14415 table_id: # (test.t1) -master-bin.000001 14415 Write_rows 1 14449 table_id: # flags: STMT_END_F -master-bin.000001 14449 Table_map 1 14490 table_id: # (test.t1) -master-bin.000001 14490 Write_rows 1 14524 table_id: # flags: STMT_END_F -master-bin.000001 14524 Table_map 1 14565 table_id: # (test.t1) -master-bin.000001 14565 Write_rows 1 14599 table_id: # flags: STMT_END_F -master-bin.000001 14599 Table_map 1 14640 table_id: # (test.t1) -master-bin.000001 14640 Write_rows 1 14674 table_id: # flags: STMT_END_F -master-bin.000001 14674 Table_map 1 14715 table_id: # (test.t1) -master-bin.000001 14715 Write_rows 1 14749 table_id: # flags: STMT_END_F -master-bin.000001 14749 Table_map 1 14790 table_id: # (test.t1) -master-bin.000001 14790 Write_rows 1 14824 table_id: # flags: STMT_END_F -master-bin.000001 14824 Table_map 1 14865 table_id: # (test.t1) -master-bin.000001 14865 Write_rows 1 14899 table_id: # flags: STMT_END_F -master-bin.000001 14899 Table_map 1 14940 table_id: # (test.t1) -master-bin.000001 14940 Write_rows 1 14974 table_id: # flags: STMT_END_F -master-bin.000001 14974 Table_map 1 15015 table_id: # (test.t1) -master-bin.000001 15015 Write_rows 1 15049 table_id: # flags: STMT_END_F -master-bin.000001 15049 Table_map 1 15090 table_id: # (test.t1) -master-bin.000001 15090 Write_rows 1 15124 table_id: # flags: STMT_END_F -master-bin.000001 15124 Table_map 1 15165 table_id: # (test.t1) -master-bin.000001 15165 Write_rows 1 15199 table_id: # flags: STMT_END_F -master-bin.000001 15199 Table_map 1 15240 table_id: # (test.t1) -master-bin.000001 15240 Write_rows 1 15274 table_id: # flags: STMT_END_F -master-bin.000001 15274 Table_map 1 15315 table_id: # (test.t1) -master-bin.000001 15315 Write_rows 1 15349 table_id: # flags: STMT_END_F -master-bin.000001 15349 Table_map 1 15390 table_id: # (test.t1) -master-bin.000001 15390 Write_rows 1 15424 table_id: # flags: STMT_END_F -master-bin.000001 15424 Table_map 1 15465 table_id: # (test.t1) -master-bin.000001 15465 Write_rows 1 15499 table_id: # flags: STMT_END_F -master-bin.000001 15499 Table_map 1 15540 table_id: # (test.t1) -master-bin.000001 15540 Write_rows 1 15574 table_id: # flags: STMT_END_F -master-bin.000001 15574 Table_map 1 15615 table_id: # (test.t1) -master-bin.000001 15615 Write_rows 1 15649 table_id: # flags: STMT_END_F -master-bin.000001 15649 Table_map 1 15690 table_id: # (test.t1) -master-bin.000001 15690 Write_rows 1 15724 table_id: # flags: STMT_END_F -master-bin.000001 15724 Table_map 1 15765 table_id: # (test.t1) -master-bin.000001 15765 Write_rows 1 15799 table_id: # flags: STMT_END_F -master-bin.000001 15799 Table_map 1 15840 table_id: # (test.t1) -master-bin.000001 15840 Write_rows 1 15874 table_id: # flags: STMT_END_F -master-bin.000001 15874 Table_map 1 15915 table_id: # (test.t1) -master-bin.000001 15915 Write_rows 1 15949 table_id: # flags: STMT_END_F -master-bin.000001 15949 Table_map 1 15990 table_id: # (test.t1) -master-bin.000001 15990 Write_rows 1 16024 table_id: # flags: STMT_END_F -master-bin.000001 16024 Table_map 1 16065 table_id: # (test.t1) -master-bin.000001 16065 Write_rows 1 16099 table_id: # flags: STMT_END_F -master-bin.000001 16099 Table_map 1 16140 table_id: # (test.t1) -master-bin.000001 16140 Write_rows 1 16174 table_id: # flags: STMT_END_F -master-bin.000001 16174 Table_map 1 16215 table_id: # (test.t1) -master-bin.000001 16215 Write_rows 1 16249 table_id: # flags: STMT_END_F -master-bin.000001 16249 Table_map 1 16290 table_id: # (test.t1) -master-bin.000001 16290 Write_rows 1 16324 table_id: # flags: STMT_END_F -master-bin.000001 16324 Table_map 1 16365 table_id: # (test.t1) -master-bin.000001 16365 Write_rows 1 16399 table_id: # flags: STMT_END_F -master-bin.000001 16399 Table_map 1 16440 table_id: # (test.t1) -master-bin.000001 16440 Write_rows 1 16474 table_id: # flags: STMT_END_F -master-bin.000001 16474 Table_map 1 16515 table_id: # (test.t1) -master-bin.000001 16515 Write_rows 1 16549 table_id: # flags: STMT_END_F -master-bin.000001 16549 Table_map 1 16590 table_id: # (test.t1) -master-bin.000001 16590 Write_rows 1 16624 table_id: # flags: STMT_END_F -master-bin.000001 16624 Table_map 1 16665 table_id: # (test.t1) -master-bin.000001 16665 Write_rows 1 16699 table_id: # flags: STMT_END_F -master-bin.000001 16699 Table_map 1 16740 table_id: # (test.t1) -master-bin.000001 16740 Write_rows 1 16774 table_id: # flags: STMT_END_F -master-bin.000001 16774 Table_map 1 16815 table_id: # (test.t1) -master-bin.000001 16815 Write_rows 1 16849 table_id: # flags: STMT_END_F -master-bin.000001 16849 Table_map 1 16890 table_id: # (test.t1) -master-bin.000001 16890 Write_rows 1 16924 table_id: # flags: STMT_END_F -master-bin.000001 16924 Table_map 1 16965 table_id: # (test.t1) -master-bin.000001 16965 Write_rows 1 16999 table_id: # flags: STMT_END_F -master-bin.000001 16999 Table_map 1 17040 table_id: # (test.t1) -master-bin.000001 17040 Write_rows 1 17074 table_id: # flags: STMT_END_F -master-bin.000001 17074 Table_map 1 17115 table_id: # (test.t1) -master-bin.000001 17115 Write_rows 1 17149 table_id: # flags: STMT_END_F -master-bin.000001 17149 Table_map 1 17190 table_id: # (test.t1) -master-bin.000001 17190 Write_rows 1 17224 table_id: # flags: STMT_END_F -master-bin.000001 17224 Table_map 1 17265 table_id: # (test.t1) -master-bin.000001 17265 Write_rows 1 17299 table_id: # flags: STMT_END_F -master-bin.000001 17299 Table_map 1 17340 table_id: # (test.t1) -master-bin.000001 17340 Write_rows 1 17374 table_id: # flags: STMT_END_F -master-bin.000001 17374 Table_map 1 17415 table_id: # (test.t1) -master-bin.000001 17415 Write_rows 1 17449 table_id: # flags: STMT_END_F -master-bin.000001 17449 Table_map 1 17490 table_id: # (test.t1) -master-bin.000001 17490 Write_rows 1 17524 table_id: # flags: STMT_END_F -master-bin.000001 17524 Table_map 1 17565 table_id: # (test.t1) -master-bin.000001 17565 Write_rows 1 17599 table_id: # flags: STMT_END_F -master-bin.000001 17599 Table_map 1 17640 table_id: # (test.t1) -master-bin.000001 17640 Write_rows 1 17674 table_id: # flags: STMT_END_F -master-bin.000001 17674 Table_map 1 17715 table_id: # (test.t1) -master-bin.000001 17715 Write_rows 1 17749 table_id: # flags: STMT_END_F -master-bin.000001 17749 Table_map 1 17790 table_id: # (test.t1) -master-bin.000001 17790 Write_rows 1 17824 table_id: # flags: STMT_END_F -master-bin.000001 17824 Table_map 1 17865 table_id: # (test.t1) -master-bin.000001 17865 Write_rows 1 17899 table_id: # flags: STMT_END_F -master-bin.000001 17899 Table_map 1 17940 table_id: # (test.t1) -master-bin.000001 17940 Write_rows 1 17974 table_id: # flags: STMT_END_F -master-bin.000001 17974 Table_map 1 18015 table_id: # (test.t1) -master-bin.000001 18015 Write_rows 1 18049 table_id: # flags: STMT_END_F -master-bin.000001 18049 Table_map 1 18090 table_id: # (test.t1) -master-bin.000001 18090 Write_rows 1 18124 table_id: # flags: STMT_END_F -master-bin.000001 18124 Table_map 1 18165 table_id: # (test.t1) -master-bin.000001 18165 Write_rows 1 18199 table_id: # flags: STMT_END_F -master-bin.000001 18199 Table_map 1 18240 table_id: # (test.t1) -master-bin.000001 18240 Write_rows 1 18274 table_id: # flags: STMT_END_F -master-bin.000001 18274 Table_map 1 18315 table_id: # (test.t1) -master-bin.000001 18315 Write_rows 1 18349 table_id: # flags: STMT_END_F -master-bin.000001 18349 Table_map 1 18390 table_id: # (test.t1) -master-bin.000001 18390 Write_rows 1 18424 table_id: # flags: STMT_END_F -master-bin.000001 18424 Table_map 1 18465 table_id: # (test.t1) -master-bin.000001 18465 Write_rows 1 18499 table_id: # flags: STMT_END_F -master-bin.000001 18499 Table_map 1 18540 table_id: # (test.t1) -master-bin.000001 18540 Write_rows 1 18574 table_id: # flags: STMT_END_F -master-bin.000001 18574 Table_map 1 18615 table_id: # (test.t1) -master-bin.000001 18615 Write_rows 1 18649 table_id: # flags: STMT_END_F -master-bin.000001 18649 Table_map 1 18690 table_id: # (test.t1) -master-bin.000001 18690 Write_rows 1 18724 table_id: # flags: STMT_END_F -master-bin.000001 18724 Table_map 1 18765 table_id: # (test.t1) -master-bin.000001 18765 Write_rows 1 18799 table_id: # flags: STMT_END_F -master-bin.000001 18799 Table_map 1 18840 table_id: # (test.t1) -master-bin.000001 18840 Write_rows 1 18874 table_id: # flags: STMT_END_F -master-bin.000001 18874 Table_map 1 18915 table_id: # (test.t1) -master-bin.000001 18915 Write_rows 1 18949 table_id: # flags: STMT_END_F -master-bin.000001 18949 Table_map 1 18990 table_id: # (test.t1) -master-bin.000001 18990 Write_rows 1 19024 table_id: # flags: STMT_END_F -master-bin.000001 19024 Table_map 1 19065 table_id: # (test.t1) -master-bin.000001 19065 Write_rows 1 19099 table_id: # flags: STMT_END_F -master-bin.000001 19099 Table_map 1 19140 table_id: # (test.t1) -master-bin.000001 19140 Write_rows 1 19174 table_id: # flags: STMT_END_F -master-bin.000001 19174 Table_map 1 19215 table_id: # (test.t1) -master-bin.000001 19215 Write_rows 1 19249 table_id: # flags: STMT_END_F -master-bin.000001 19249 Table_map 1 19290 table_id: # (test.t1) -master-bin.000001 19290 Write_rows 1 19324 table_id: # flags: STMT_END_F -master-bin.000001 19324 Table_map 1 19365 table_id: # (test.t1) -master-bin.000001 19365 Write_rows 1 19399 table_id: # flags: STMT_END_F -master-bin.000001 19399 Table_map 1 19440 table_id: # (test.t1) -master-bin.000001 19440 Write_rows 1 19474 table_id: # flags: STMT_END_F -master-bin.000001 19474 Table_map 1 19515 table_id: # (test.t1) -master-bin.000001 19515 Write_rows 1 19549 table_id: # flags: STMT_END_F -master-bin.000001 19549 Table_map 1 19590 table_id: # (test.t1) -master-bin.000001 19590 Write_rows 1 19624 table_id: # flags: STMT_END_F -master-bin.000001 19624 Table_map 1 19665 table_id: # (test.t1) -master-bin.000001 19665 Write_rows 1 19699 table_id: # flags: STMT_END_F -master-bin.000001 19699 Table_map 1 19740 table_id: # (test.t1) -master-bin.000001 19740 Write_rows 1 19774 table_id: # flags: STMT_END_F -master-bin.000001 19774 Table_map 1 19815 table_id: # (test.t1) -master-bin.000001 19815 Write_rows 1 19849 table_id: # flags: STMT_END_F -master-bin.000001 19849 Table_map 1 19890 table_id: # (test.t1) -master-bin.000001 19890 Write_rows 1 19924 table_id: # flags: STMT_END_F -master-bin.000001 19924 Table_map 1 19965 table_id: # (test.t1) -master-bin.000001 19965 Write_rows 1 19999 table_id: # flags: STMT_END_F -master-bin.000001 19999 Table_map 1 20040 table_id: # (test.t1) -master-bin.000001 20040 Write_rows 1 20074 table_id: # flags: STMT_END_F -master-bin.000001 20074 Table_map 1 20115 table_id: # (test.t1) -master-bin.000001 20115 Write_rows 1 20149 table_id: # flags: STMT_END_F -master-bin.000001 20149 Table_map 1 20190 table_id: # (test.t1) -master-bin.000001 20190 Write_rows 1 20224 table_id: # flags: STMT_END_F -master-bin.000001 20224 Table_map 1 20265 table_id: # (test.t1) -master-bin.000001 20265 Write_rows 1 20299 table_id: # flags: STMT_END_F -master-bin.000001 20299 Table_map 1 20340 table_id: # (test.t1) -master-bin.000001 20340 Write_rows 1 20374 table_id: # flags: STMT_END_F -master-bin.000001 20374 Table_map 1 20415 table_id: # (test.t1) -master-bin.000001 20415 Write_rows 1 20449 table_id: # flags: STMT_END_F -master-bin.000001 20449 Table_map 1 20490 table_id: # (test.t1) -master-bin.000001 20490 Write_rows 1 20524 table_id: # flags: STMT_END_F -master-bin.000001 20524 Table_map 1 20565 table_id: # (test.t1) -master-bin.000001 20565 Write_rows 1 20599 table_id: # flags: STMT_END_F -master-bin.000001 20599 Table_map 1 20640 table_id: # (test.t1) -master-bin.000001 20640 Write_rows 1 20674 table_id: # flags: STMT_END_F -master-bin.000001 20674 Table_map 1 20715 table_id: # (test.t1) -master-bin.000001 20715 Write_rows 1 20749 table_id: # flags: STMT_END_F -master-bin.000001 20749 Table_map 1 20790 table_id: # (test.t1) -master-bin.000001 20790 Write_rows 1 20824 table_id: # flags: STMT_END_F -master-bin.000001 20824 Table_map 1 20865 table_id: # (test.t1) -master-bin.000001 20865 Write_rows 1 20899 table_id: # flags: STMT_END_F -master-bin.000001 20899 Table_map 1 20940 table_id: # (test.t1) -master-bin.000001 20940 Write_rows 1 20974 table_id: # flags: STMT_END_F -master-bin.000001 20974 Table_map 1 21015 table_id: # (test.t1) -master-bin.000001 21015 Write_rows 1 21049 table_id: # flags: STMT_END_F -master-bin.000001 21049 Table_map 1 21090 table_id: # (test.t1) -master-bin.000001 21090 Write_rows 1 21124 table_id: # flags: STMT_END_F -master-bin.000001 21124 Table_map 1 21165 table_id: # (test.t1) -master-bin.000001 21165 Write_rows 1 21199 table_id: # flags: STMT_END_F -master-bin.000001 21199 Table_map 1 21240 table_id: # (test.t1) -master-bin.000001 21240 Write_rows 1 21274 table_id: # flags: STMT_END_F -master-bin.000001 21274 Table_map 1 21315 table_id: # (test.t1) -master-bin.000001 21315 Write_rows 1 21349 table_id: # flags: STMT_END_F -master-bin.000001 21349 Table_map 1 21390 table_id: # (test.t1) -master-bin.000001 21390 Write_rows 1 21424 table_id: # flags: STMT_END_F -master-bin.000001 21424 Table_map 1 21465 table_id: # (test.t1) -master-bin.000001 21465 Write_rows 1 21499 table_id: # flags: STMT_END_F -master-bin.000001 21499 Table_map 1 21540 table_id: # (test.t1) -master-bin.000001 21540 Write_rows 1 21574 table_id: # flags: STMT_END_F -master-bin.000001 21574 Table_map 1 21615 table_id: # (test.t1) -master-bin.000001 21615 Write_rows 1 21649 table_id: # flags: STMT_END_F -master-bin.000001 21649 Table_map 1 21690 table_id: # (test.t1) -master-bin.000001 21690 Write_rows 1 21724 table_id: # flags: STMT_END_F -master-bin.000001 21724 Table_map 1 21765 table_id: # (test.t1) -master-bin.000001 21765 Write_rows 1 21799 table_id: # flags: STMT_END_F -master-bin.000001 21799 Table_map 1 21840 table_id: # (test.t1) -master-bin.000001 21840 Write_rows 1 21874 table_id: # flags: STMT_END_F -master-bin.000001 21874 Table_map 1 21915 table_id: # (test.t1) -master-bin.000001 21915 Write_rows 1 21949 table_id: # flags: STMT_END_F -master-bin.000001 21949 Table_map 1 21990 table_id: # (test.t1) -master-bin.000001 21990 Write_rows 1 22024 table_id: # flags: STMT_END_F -master-bin.000001 22024 Table_map 1 22065 table_id: # (test.t1) -master-bin.000001 22065 Write_rows 1 22099 table_id: # flags: STMT_END_F -master-bin.000001 22099 Table_map 1 22140 table_id: # (test.t1) -master-bin.000001 22140 Write_rows 1 22174 table_id: # flags: STMT_END_F -master-bin.000001 22174 Table_map 1 22215 table_id: # (test.t1) -master-bin.000001 22215 Write_rows 1 22249 table_id: # flags: STMT_END_F -master-bin.000001 22249 Table_map 1 22290 table_id: # (test.t1) -master-bin.000001 22290 Write_rows 1 22324 table_id: # flags: STMT_END_F -master-bin.000001 22324 Table_map 1 22365 table_id: # (test.t1) -master-bin.000001 22365 Write_rows 1 22399 table_id: # flags: STMT_END_F -master-bin.000001 22399 Table_map 1 22440 table_id: # (test.t1) -master-bin.000001 22440 Write_rows 1 22474 table_id: # flags: STMT_END_F -master-bin.000001 22474 Table_map 1 22515 table_id: # (test.t1) -master-bin.000001 22515 Write_rows 1 22549 table_id: # flags: STMT_END_F -master-bin.000001 22549 Table_map 1 22590 table_id: # (test.t1) -master-bin.000001 22590 Write_rows 1 22624 table_id: # flags: STMT_END_F -master-bin.000001 22624 Table_map 1 22665 table_id: # (test.t1) -master-bin.000001 22665 Write_rows 1 22699 table_id: # flags: STMT_END_F -master-bin.000001 22699 Table_map 1 22740 table_id: # (test.t1) -master-bin.000001 22740 Write_rows 1 22774 table_id: # flags: STMT_END_F -master-bin.000001 22774 Table_map 1 22815 table_id: # (test.t1) -master-bin.000001 22815 Write_rows 1 22849 table_id: # flags: STMT_END_F -master-bin.000001 22849 Table_map 1 22890 table_id: # (test.t1) -master-bin.000001 22890 Write_rows 1 22924 table_id: # flags: STMT_END_F -master-bin.000001 22924 Table_map 1 22965 table_id: # (test.t1) -master-bin.000001 22965 Write_rows 1 22999 table_id: # flags: STMT_END_F -master-bin.000001 22999 Table_map 1 23040 table_id: # (test.t1) -master-bin.000001 23040 Write_rows 1 23074 table_id: # flags: STMT_END_F -master-bin.000001 23074 Table_map 1 23115 table_id: # (test.t1) -master-bin.000001 23115 Write_rows 1 23149 table_id: # flags: STMT_END_F -master-bin.000001 23149 Table_map 1 23190 table_id: # (test.t1) -master-bin.000001 23190 Write_rows 1 23224 table_id: # flags: STMT_END_F -master-bin.000001 23224 Table_map 1 23265 table_id: # (test.t1) -master-bin.000001 23265 Write_rows 1 23299 table_id: # flags: STMT_END_F -master-bin.000001 23299 Table_map 1 23340 table_id: # (test.t1) -master-bin.000001 23340 Write_rows 1 23374 table_id: # flags: STMT_END_F -master-bin.000001 23374 Table_map 1 23415 table_id: # (test.t1) -master-bin.000001 23415 Write_rows 1 23449 table_id: # flags: STMT_END_F -master-bin.000001 23449 Table_map 1 23490 table_id: # (test.t1) -master-bin.000001 23490 Write_rows 1 23524 table_id: # flags: STMT_END_F -master-bin.000001 23524 Table_map 1 23565 table_id: # (test.t1) -master-bin.000001 23565 Write_rows 1 23599 table_id: # flags: STMT_END_F -master-bin.000001 23599 Table_map 1 23640 table_id: # (test.t1) -master-bin.000001 23640 Write_rows 1 23674 table_id: # flags: STMT_END_F -master-bin.000001 23674 Table_map 1 23715 table_id: # (test.t1) -master-bin.000001 23715 Write_rows 1 23749 table_id: # flags: STMT_END_F -master-bin.000001 23749 Table_map 1 23790 table_id: # (test.t1) -master-bin.000001 23790 Write_rows 1 23824 table_id: # flags: STMT_END_F -master-bin.000001 23824 Table_map 1 23865 table_id: # (test.t1) -master-bin.000001 23865 Write_rows 1 23899 table_id: # flags: STMT_END_F -master-bin.000001 23899 Table_map 1 23940 table_id: # (test.t1) -master-bin.000001 23940 Write_rows 1 23974 table_id: # flags: STMT_END_F -master-bin.000001 23974 Table_map 1 24015 table_id: # (test.t1) -master-bin.000001 24015 Write_rows 1 24049 table_id: # flags: STMT_END_F -master-bin.000001 24049 Table_map 1 24090 table_id: # (test.t1) -master-bin.000001 24090 Write_rows 1 24124 table_id: # flags: STMT_END_F -master-bin.000001 24124 Table_map 1 24165 table_id: # (test.t1) -master-bin.000001 24165 Write_rows 1 24199 table_id: # flags: STMT_END_F -master-bin.000001 24199 Table_map 1 24240 table_id: # (test.t1) -master-bin.000001 24240 Write_rows 1 24274 table_id: # flags: STMT_END_F -master-bin.000001 24274 Table_map 1 24315 table_id: # (test.t1) -master-bin.000001 24315 Write_rows 1 24349 table_id: # flags: STMT_END_F -master-bin.000001 24349 Table_map 1 24390 table_id: # (test.t1) -master-bin.000001 24390 Write_rows 1 24424 table_id: # flags: STMT_END_F -master-bin.000001 24424 Table_map 1 24465 table_id: # (test.t1) -master-bin.000001 24465 Write_rows 1 24499 table_id: # flags: STMT_END_F -master-bin.000001 24499 Table_map 1 24540 table_id: # (test.t1) -master-bin.000001 24540 Write_rows 1 24574 table_id: # flags: STMT_END_F -master-bin.000001 24574 Table_map 1 24615 table_id: # (test.t1) -master-bin.000001 24615 Write_rows 1 24649 table_id: # flags: STMT_END_F -master-bin.000001 24649 Table_map 1 24690 table_id: # (test.t1) -master-bin.000001 24690 Write_rows 1 24724 table_id: # flags: STMT_END_F -master-bin.000001 24724 Table_map 1 24765 table_id: # (test.t1) -master-bin.000001 24765 Write_rows 1 24799 table_id: # flags: STMT_END_F -master-bin.000001 24799 Table_map 1 24840 table_id: # (test.t1) -master-bin.000001 24840 Write_rows 1 24874 table_id: # flags: STMT_END_F -master-bin.000001 24874 Table_map 1 24915 table_id: # (test.t1) -master-bin.000001 24915 Write_rows 1 24949 table_id: # flags: STMT_END_F -master-bin.000001 24949 Table_map 1 24990 table_id: # (test.t1) -master-bin.000001 24990 Write_rows 1 25024 table_id: # flags: STMT_END_F -master-bin.000001 25024 Table_map 1 25065 table_id: # (test.t1) -master-bin.000001 25065 Write_rows 1 25099 table_id: # flags: STMT_END_F -master-bin.000001 25099 Table_map 1 25140 table_id: # (test.t1) -master-bin.000001 25140 Write_rows 1 25174 table_id: # flags: STMT_END_F -master-bin.000001 25174 Table_map 1 25215 table_id: # (test.t1) -master-bin.000001 25215 Write_rows 1 25249 table_id: # flags: STMT_END_F -master-bin.000001 25249 Table_map 1 25290 table_id: # (test.t1) -master-bin.000001 25290 Write_rows 1 25324 table_id: # flags: STMT_END_F -master-bin.000001 25324 Table_map 1 25365 table_id: # (test.t1) -master-bin.000001 25365 Write_rows 1 25399 table_id: # flags: STMT_END_F -master-bin.000001 25399 Table_map 1 25440 table_id: # (test.t1) -master-bin.000001 25440 Write_rows 1 25474 table_id: # flags: STMT_END_F -master-bin.000001 25474 Table_map 1 25515 table_id: # (test.t1) -master-bin.000001 25515 Write_rows 1 25549 table_id: # flags: STMT_END_F -master-bin.000001 25549 Table_map 1 25590 table_id: # (test.t1) -master-bin.000001 25590 Write_rows 1 25624 table_id: # flags: STMT_END_F -master-bin.000001 25624 Table_map 1 25665 table_id: # (test.t1) -master-bin.000001 25665 Write_rows 1 25699 table_id: # flags: STMT_END_F -master-bin.000001 25699 Table_map 1 25740 table_id: # (test.t1) -master-bin.000001 25740 Write_rows 1 25774 table_id: # flags: STMT_END_F -master-bin.000001 25774 Table_map 1 25815 table_id: # (test.t1) -master-bin.000001 25815 Write_rows 1 25849 table_id: # flags: STMT_END_F -master-bin.000001 25849 Table_map 1 25890 table_id: # (test.t1) -master-bin.000001 25890 Write_rows 1 25924 table_id: # flags: STMT_END_F -master-bin.000001 25924 Table_map 1 25965 table_id: # (test.t1) -master-bin.000001 25965 Write_rows 1 25999 table_id: # flags: STMT_END_F -master-bin.000001 25999 Table_map 1 26040 table_id: # (test.t1) -master-bin.000001 26040 Write_rows 1 26074 table_id: # flags: STMT_END_F -master-bin.000001 26074 Table_map 1 26115 table_id: # (test.t1) -master-bin.000001 26115 Write_rows 1 26149 table_id: # flags: STMT_END_F -master-bin.000001 26149 Table_map 1 26190 table_id: # (test.t1) -master-bin.000001 26190 Write_rows 1 26224 table_id: # flags: STMT_END_F -master-bin.000001 26224 Table_map 1 26265 table_id: # (test.t1) -master-bin.000001 26265 Write_rows 1 26299 table_id: # flags: STMT_END_F -master-bin.000001 26299 Table_map 1 26340 table_id: # (test.t1) -master-bin.000001 26340 Write_rows 1 26374 table_id: # flags: STMT_END_F -master-bin.000001 26374 Table_map 1 26415 table_id: # (test.t1) -master-bin.000001 26415 Write_rows 1 26449 table_id: # flags: STMT_END_F -master-bin.000001 26449 Table_map 1 26490 table_id: # (test.t1) -master-bin.000001 26490 Write_rows 1 26524 table_id: # flags: STMT_END_F -master-bin.000001 26524 Table_map 1 26565 table_id: # (test.t1) -master-bin.000001 26565 Write_rows 1 26599 table_id: # flags: STMT_END_F -master-bin.000001 26599 Table_map 1 26640 table_id: # (test.t1) -master-bin.000001 26640 Write_rows 1 26674 table_id: # flags: STMT_END_F -master-bin.000001 26674 Table_map 1 26715 table_id: # (test.t1) -master-bin.000001 26715 Write_rows 1 26749 table_id: # flags: STMT_END_F -master-bin.000001 26749 Table_map 1 26790 table_id: # (test.t1) -master-bin.000001 26790 Write_rows 1 26824 table_id: # flags: STMT_END_F -master-bin.000001 26824 Table_map 1 26865 table_id: # (test.t1) -master-bin.000001 26865 Write_rows 1 26899 table_id: # flags: STMT_END_F -master-bin.000001 26899 Table_map 1 26940 table_id: # (test.t1) -master-bin.000001 26940 Write_rows 1 26974 table_id: # flags: STMT_END_F -master-bin.000001 26974 Table_map 1 27015 table_id: # (test.t1) -master-bin.000001 27015 Write_rows 1 27049 table_id: # flags: STMT_END_F -master-bin.000001 27049 Table_map 1 27090 table_id: # (test.t1) -master-bin.000001 27090 Write_rows 1 27124 table_id: # flags: STMT_END_F -master-bin.000001 27124 Table_map 1 27165 table_id: # (test.t1) -master-bin.000001 27165 Write_rows 1 27199 table_id: # flags: STMT_END_F -master-bin.000001 27199 Table_map 1 27240 table_id: # (test.t1) -master-bin.000001 27240 Write_rows 1 27274 table_id: # flags: STMT_END_F -master-bin.000001 27274 Table_map 1 27315 table_id: # (test.t1) -master-bin.000001 27315 Write_rows 1 27349 table_id: # flags: STMT_END_F -master-bin.000001 27349 Table_map 1 27390 table_id: # (test.t1) -master-bin.000001 27390 Write_rows 1 27424 table_id: # flags: STMT_END_F -master-bin.000001 27424 Table_map 1 27465 table_id: # (test.t1) -master-bin.000001 27465 Write_rows 1 27499 table_id: # flags: STMT_END_F -master-bin.000001 27499 Table_map 1 27540 table_id: # (test.t1) -master-bin.000001 27540 Write_rows 1 27574 table_id: # flags: STMT_END_F -master-bin.000001 27574 Table_map 1 27615 table_id: # (test.t1) -master-bin.000001 27615 Write_rows 1 27649 table_id: # flags: STMT_END_F -master-bin.000001 27649 Table_map 1 27690 table_id: # (test.t1) -master-bin.000001 27690 Write_rows 1 27724 table_id: # flags: STMT_END_F -master-bin.000001 27724 Table_map 1 27765 table_id: # (test.t1) -master-bin.000001 27765 Write_rows 1 27799 table_id: # flags: STMT_END_F -master-bin.000001 27799 Table_map 1 27840 table_id: # (test.t1) -master-bin.000001 27840 Write_rows 1 27874 table_id: # flags: STMT_END_F -master-bin.000001 27874 Table_map 1 27915 table_id: # (test.t1) -master-bin.000001 27915 Write_rows 1 27949 table_id: # flags: STMT_END_F -master-bin.000001 27949 Table_map 1 27990 table_id: # (test.t1) -master-bin.000001 27990 Write_rows 1 28024 table_id: # flags: STMT_END_F -master-bin.000001 28024 Table_map 1 28065 table_id: # (test.t1) -master-bin.000001 28065 Write_rows 1 28099 table_id: # flags: STMT_END_F -master-bin.000001 28099 Table_map 1 28140 table_id: # (test.t1) -master-bin.000001 28140 Write_rows 1 28174 table_id: # flags: STMT_END_F -master-bin.000001 28174 Table_map 1 28215 table_id: # (test.t1) -master-bin.000001 28215 Write_rows 1 28249 table_id: # flags: STMT_END_F -master-bin.000001 28249 Table_map 1 28290 table_id: # (test.t1) -master-bin.000001 28290 Write_rows 1 28324 table_id: # flags: STMT_END_F -master-bin.000001 28324 Table_map 1 28365 table_id: # (test.t1) -master-bin.000001 28365 Write_rows 1 28399 table_id: # flags: STMT_END_F -master-bin.000001 28399 Table_map 1 28440 table_id: # (test.t1) -master-bin.000001 28440 Write_rows 1 28474 table_id: # flags: STMT_END_F -master-bin.000001 28474 Table_map 1 28515 table_id: # (test.t1) -master-bin.000001 28515 Write_rows 1 28549 table_id: # flags: STMT_END_F -master-bin.000001 28549 Table_map 1 28590 table_id: # (test.t1) -master-bin.000001 28590 Write_rows 1 28624 table_id: # flags: STMT_END_F -master-bin.000001 28624 Table_map 1 28665 table_id: # (test.t1) -master-bin.000001 28665 Write_rows 1 28699 table_id: # flags: STMT_END_F -master-bin.000001 28699 Table_map 1 28740 table_id: # (test.t1) -master-bin.000001 28740 Write_rows 1 28774 table_id: # flags: STMT_END_F -master-bin.000001 28774 Table_map 1 28815 table_id: # (test.t1) -master-bin.000001 28815 Write_rows 1 28849 table_id: # flags: STMT_END_F -master-bin.000001 28849 Table_map 1 28890 table_id: # (test.t1) -master-bin.000001 28890 Write_rows 1 28924 table_id: # flags: STMT_END_F -master-bin.000001 28924 Table_map 1 28965 table_id: # (test.t1) -master-bin.000001 28965 Write_rows 1 28999 table_id: # flags: STMT_END_F -master-bin.000001 28999 Table_map 1 29040 table_id: # (test.t1) -master-bin.000001 29040 Write_rows 1 29074 table_id: # flags: STMT_END_F -master-bin.000001 29074 Table_map 1 29115 table_id: # (test.t1) -master-bin.000001 29115 Write_rows 1 29149 table_id: # flags: STMT_END_F -master-bin.000001 29149 Table_map 1 29190 table_id: # (test.t1) -master-bin.000001 29190 Write_rows 1 29224 table_id: # flags: STMT_END_F -master-bin.000001 29224 Table_map 1 29265 table_id: # (test.t1) -master-bin.000001 29265 Write_rows 1 29299 table_id: # flags: STMT_END_F -master-bin.000001 29299 Table_map 1 29340 table_id: # (test.t1) -master-bin.000001 29340 Write_rows 1 29374 table_id: # flags: STMT_END_F -master-bin.000001 29374 Table_map 1 29415 table_id: # (test.t1) -master-bin.000001 29415 Write_rows 1 29449 table_id: # flags: STMT_END_F -master-bin.000001 29449 Table_map 1 29490 table_id: # (test.t1) -master-bin.000001 29490 Write_rows 1 29524 table_id: # flags: STMT_END_F -master-bin.000001 29524 Table_map 1 29565 table_id: # (test.t1) -master-bin.000001 29565 Write_rows 1 29599 table_id: # flags: STMT_END_F -master-bin.000001 29599 Table_map 1 29640 table_id: # (test.t1) -master-bin.000001 29640 Write_rows 1 29674 table_id: # flags: STMT_END_F -master-bin.000001 29674 Table_map 1 29715 table_id: # (test.t1) -master-bin.000001 29715 Write_rows 1 29749 table_id: # flags: STMT_END_F -master-bin.000001 29749 Table_map 1 29790 table_id: # (test.t1) -master-bin.000001 29790 Write_rows 1 29824 table_id: # flags: STMT_END_F -master-bin.000001 29824 Table_map 1 29865 table_id: # (test.t1) -master-bin.000001 29865 Write_rows 1 29899 table_id: # flags: STMT_END_F -master-bin.000001 29899 Table_map 1 29940 table_id: # (test.t1) -master-bin.000001 29940 Write_rows 1 29974 table_id: # flags: STMT_END_F -master-bin.000001 29974 Table_map 1 30015 table_id: # (test.t1) -master-bin.000001 30015 Write_rows 1 30049 table_id: # flags: STMT_END_F -master-bin.000001 30049 Table_map 1 30090 table_id: # (test.t1) -master-bin.000001 30090 Write_rows 1 30124 table_id: # flags: STMT_END_F -master-bin.000001 30124 Table_map 1 30165 table_id: # (test.t1) -master-bin.000001 30165 Write_rows 1 30199 table_id: # flags: STMT_END_F -master-bin.000001 30199 Table_map 1 30240 table_id: # (test.t1) -master-bin.000001 30240 Write_rows 1 30274 table_id: # flags: STMT_END_F -master-bin.000001 30274 Xid 1 30301 COMMIT /* XID */ -master-bin.000001 30301 Rotate 1 30345 master-bin.000002;pos=4 +master-bin.000001 499 Xid 1 526 COMMIT /* XID */ +master-bin.000001 526 Query 1 602 use `test`; drop table t1 +set @bcs = @@binlog_cache_size; +set global binlog_cache_size=4096; +reset master; +create table t1 (a int) engine=innodb; +show binlog events from 0; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 107 Server version, Binlog ver: 4 +master-bin.000001 107 Query 1 207 use `test`; create table t1 (a int) engine=innodb +master-bin.000001 207 Query 1 275 use `test`; BEGIN +master-bin.000001 275 Table_map 1 316 table_id: # (test.t1) +master-bin.000001 316 Write_rows 1 350 table_id: # flags: STMT_END_F +master-bin.000001 350 Table_map 1 391 table_id: # (test.t1) +master-bin.000001 391 Write_rows 1 425 table_id: # flags: STMT_END_F +master-bin.000001 425 Table_map 1 466 table_id: # (test.t1) +master-bin.000001 466 Write_rows 1 500 table_id: # flags: STMT_END_F +master-bin.000001 500 Table_map 1 541 table_id: # (test.t1) +master-bin.000001 541 Write_rows 1 575 table_id: # flags: STMT_END_F +master-bin.000001 575 Table_map 1 616 table_id: # (test.t1) +master-bin.000001 616 Write_rows 1 650 table_id: # flags: STMT_END_F +master-bin.000001 650 Table_map 1 691 table_id: # (test.t1) +master-bin.000001 691 Write_rows 1 725 table_id: # flags: STMT_END_F +master-bin.000001 725 Table_map 1 766 table_id: # (test.t1) +master-bin.000001 766 Write_rows 1 800 table_id: # flags: STMT_END_F +master-bin.000001 800 Table_map 1 841 table_id: # (test.t1) +master-bin.000001 841 Write_rows 1 875 table_id: # flags: STMT_END_F +master-bin.000001 875 Table_map 1 916 table_id: # (test.t1) +master-bin.000001 916 Write_rows 1 950 table_id: # flags: STMT_END_F +master-bin.000001 950 Table_map 1 991 table_id: # (test.t1) +master-bin.000001 991 Write_rows 1 1025 table_id: # flags: STMT_END_F +master-bin.000001 1025 Table_map 1 1066 table_id: # (test.t1) +master-bin.000001 1066 Write_rows 1 1100 table_id: # flags: STMT_END_F +master-bin.000001 1100 Table_map 1 1141 table_id: # (test.t1) +master-bin.000001 1141 Write_rows 1 1175 table_id: # flags: STMT_END_F +master-bin.000001 1175 Table_map 1 1216 table_id: # (test.t1) +master-bin.000001 1216 Write_rows 1 1250 table_id: # flags: STMT_END_F +master-bin.000001 1250 Table_map 1 1291 table_id: # (test.t1) +master-bin.000001 1291 Write_rows 1 1325 table_id: # flags: STMT_END_F +master-bin.000001 1325 Table_map 1 1366 table_id: # (test.t1) +master-bin.000001 1366 Write_rows 1 1400 table_id: # flags: STMT_END_F +master-bin.000001 1400 Table_map 1 1441 table_id: # (test.t1) +master-bin.000001 1441 Write_rows 1 1475 table_id: # flags: STMT_END_F +master-bin.000001 1475 Table_map 1 1516 table_id: # (test.t1) +master-bin.000001 1516 Write_rows 1 1550 table_id: # flags: STMT_END_F +master-bin.000001 1550 Table_map 1 1591 table_id: # (test.t1) +master-bin.000001 1591 Write_rows 1 1625 table_id: # flags: STMT_END_F +master-bin.000001 1625 Table_map 1 1666 table_id: # (test.t1) +master-bin.000001 1666 Write_rows 1 1700 table_id: # flags: STMT_END_F +master-bin.000001 1700 Table_map 1 1741 table_id: # (test.t1) +master-bin.000001 1741 Write_rows 1 1775 table_id: # flags: STMT_END_F +master-bin.000001 1775 Table_map 1 1816 table_id: # (test.t1) +master-bin.000001 1816 Write_rows 1 1850 table_id: # flags: STMT_END_F +master-bin.000001 1850 Table_map 1 1891 table_id: # (test.t1) +master-bin.000001 1891 Write_rows 1 1925 table_id: # flags: STMT_END_F +master-bin.000001 1925 Table_map 1 1966 table_id: # (test.t1) +master-bin.000001 1966 Write_rows 1 2000 table_id: # flags: STMT_END_F +master-bin.000001 2000 Table_map 1 2041 table_id: # (test.t1) +master-bin.000001 2041 Write_rows 1 2075 table_id: # flags: STMT_END_F +master-bin.000001 2075 Table_map 1 2116 table_id: # (test.t1) +master-bin.000001 2116 Write_rows 1 2150 table_id: # flags: STMT_END_F +master-bin.000001 2150 Table_map 1 2191 table_id: # (test.t1) +master-bin.000001 2191 Write_rows 1 2225 table_id: # flags: STMT_END_F +master-bin.000001 2225 Table_map 1 2266 table_id: # (test.t1) +master-bin.000001 2266 Write_rows 1 2300 table_id: # flags: STMT_END_F +master-bin.000001 2300 Table_map 1 2341 table_id: # (test.t1) +master-bin.000001 2341 Write_rows 1 2375 table_id: # flags: STMT_END_F +master-bin.000001 2375 Table_map 1 2416 table_id: # (test.t1) +master-bin.000001 2416 Write_rows 1 2450 table_id: # flags: STMT_END_F +master-bin.000001 2450 Table_map 1 2491 table_id: # (test.t1) +master-bin.000001 2491 Write_rows 1 2525 table_id: # flags: STMT_END_F +master-bin.000001 2525 Table_map 1 2566 table_id: # (test.t1) +master-bin.000001 2566 Write_rows 1 2600 table_id: # flags: STMT_END_F +master-bin.000001 2600 Table_map 1 2641 table_id: # (test.t1) +master-bin.000001 2641 Write_rows 1 2675 table_id: # flags: STMT_END_F +master-bin.000001 2675 Table_map 1 2716 table_id: # (test.t1) +master-bin.000001 2716 Write_rows 1 2750 table_id: # flags: STMT_END_F +master-bin.000001 2750 Table_map 1 2791 table_id: # (test.t1) +master-bin.000001 2791 Write_rows 1 2825 table_id: # flags: STMT_END_F +master-bin.000001 2825 Table_map 1 2866 table_id: # (test.t1) +master-bin.000001 2866 Write_rows 1 2900 table_id: # flags: STMT_END_F +master-bin.000001 2900 Table_map 1 2941 table_id: # (test.t1) +master-bin.000001 2941 Write_rows 1 2975 table_id: # flags: STMT_END_F +master-bin.000001 2975 Table_map 1 3016 table_id: # (test.t1) +master-bin.000001 3016 Write_rows 1 3050 table_id: # flags: STMT_END_F +master-bin.000001 3050 Table_map 1 3091 table_id: # (test.t1) +master-bin.000001 3091 Write_rows 1 3125 table_id: # flags: STMT_END_F +master-bin.000001 3125 Table_map 1 3166 table_id: # (test.t1) +master-bin.000001 3166 Write_rows 1 3200 table_id: # flags: STMT_END_F +master-bin.000001 3200 Table_map 1 3241 table_id: # (test.t1) +master-bin.000001 3241 Write_rows 1 3275 table_id: # flags: STMT_END_F +master-bin.000001 3275 Table_map 1 3316 table_id: # (test.t1) +master-bin.000001 3316 Write_rows 1 3350 table_id: # flags: STMT_END_F +master-bin.000001 3350 Table_map 1 3391 table_id: # (test.t1) +master-bin.000001 3391 Write_rows 1 3425 table_id: # flags: STMT_END_F +master-bin.000001 3425 Table_map 1 3466 table_id: # (test.t1) +master-bin.000001 3466 Write_rows 1 3500 table_id: # flags: STMT_END_F +master-bin.000001 3500 Table_map 1 3541 table_id: # (test.t1) +master-bin.000001 3541 Write_rows 1 3575 table_id: # flags: STMT_END_F +master-bin.000001 3575 Table_map 1 3616 table_id: # (test.t1) +master-bin.000001 3616 Write_rows 1 3650 table_id: # flags: STMT_END_F +master-bin.000001 3650 Table_map 1 3691 table_id: # (test.t1) +master-bin.000001 3691 Write_rows 1 3725 table_id: # flags: STMT_END_F +master-bin.000001 3725 Table_map 1 3766 table_id: # (test.t1) +master-bin.000001 3766 Write_rows 1 3800 table_id: # flags: STMT_END_F +master-bin.000001 3800 Table_map 1 3841 table_id: # (test.t1) +master-bin.000001 3841 Write_rows 1 3875 table_id: # flags: STMT_END_F +master-bin.000001 3875 Table_map 1 3916 table_id: # (test.t1) +master-bin.000001 3916 Write_rows 1 3950 table_id: # flags: STMT_END_F +master-bin.000001 3950 Table_map 1 3991 table_id: # (test.t1) +master-bin.000001 3991 Write_rows 1 4025 table_id: # flags: STMT_END_F +master-bin.000001 4025 Table_map 1 4066 table_id: # (test.t1) +master-bin.000001 4066 Write_rows 1 4100 table_id: # flags: STMT_END_F +master-bin.000001 4100 Table_map 1 4141 table_id: # (test.t1) +master-bin.000001 4141 Write_rows 1 4175 table_id: # flags: STMT_END_F +master-bin.000001 4175 Table_map 1 4216 table_id: # (test.t1) +master-bin.000001 4216 Write_rows 1 4250 table_id: # flags: STMT_END_F +master-bin.000001 4250 Table_map 1 4291 table_id: # (test.t1) +master-bin.000001 4291 Write_rows 1 4325 table_id: # flags: STMT_END_F +master-bin.000001 4325 Table_map 1 4366 table_id: # (test.t1) +master-bin.000001 4366 Write_rows 1 4400 table_id: # flags: STMT_END_F +master-bin.000001 4400 Table_map 1 4441 table_id: # (test.t1) +master-bin.000001 4441 Write_rows 1 4475 table_id: # flags: STMT_END_F +master-bin.000001 4475 Table_map 1 4516 table_id: # (test.t1) +master-bin.000001 4516 Write_rows 1 4550 table_id: # flags: STMT_END_F +master-bin.000001 4550 Table_map 1 4591 table_id: # (test.t1) +master-bin.000001 4591 Write_rows 1 4625 table_id: # flags: STMT_END_F +master-bin.000001 4625 Table_map 1 4666 table_id: # (test.t1) +master-bin.000001 4666 Write_rows 1 4700 table_id: # flags: STMT_END_F +master-bin.000001 4700 Table_map 1 4741 table_id: # (test.t1) +master-bin.000001 4741 Write_rows 1 4775 table_id: # flags: STMT_END_F +master-bin.000001 4775 Table_map 1 4816 table_id: # (test.t1) +master-bin.000001 4816 Write_rows 1 4850 table_id: # flags: STMT_END_F +master-bin.000001 4850 Table_map 1 4891 table_id: # (test.t1) +master-bin.000001 4891 Write_rows 1 4925 table_id: # flags: STMT_END_F +master-bin.000001 4925 Table_map 1 4966 table_id: # (test.t1) +master-bin.000001 4966 Write_rows 1 5000 table_id: # flags: STMT_END_F +master-bin.000001 5000 Table_map 1 5041 table_id: # (test.t1) +master-bin.000001 5041 Write_rows 1 5075 table_id: # flags: STMT_END_F +master-bin.000001 5075 Table_map 1 5116 table_id: # (test.t1) +master-bin.000001 5116 Write_rows 1 5150 table_id: # flags: STMT_END_F +master-bin.000001 5150 Table_map 1 5191 table_id: # (test.t1) +master-bin.000001 5191 Write_rows 1 5225 table_id: # flags: STMT_END_F +master-bin.000001 5225 Table_map 1 5266 table_id: # (test.t1) +master-bin.000001 5266 Write_rows 1 5300 table_id: # flags: STMT_END_F +master-bin.000001 5300 Table_map 1 5341 table_id: # (test.t1) +master-bin.000001 5341 Write_rows 1 5375 table_id: # flags: STMT_END_F +master-bin.000001 5375 Table_map 1 5416 table_id: # (test.t1) +master-bin.000001 5416 Write_rows 1 5450 table_id: # flags: STMT_END_F +master-bin.000001 5450 Table_map 1 5491 table_id: # (test.t1) +master-bin.000001 5491 Write_rows 1 5525 table_id: # flags: STMT_END_F +master-bin.000001 5525 Table_map 1 5566 table_id: # (test.t1) +master-bin.000001 5566 Write_rows 1 5600 table_id: # flags: STMT_END_F +master-bin.000001 5600 Table_map 1 5641 table_id: # (test.t1) +master-bin.000001 5641 Write_rows 1 5675 table_id: # flags: STMT_END_F +master-bin.000001 5675 Table_map 1 5716 table_id: # (test.t1) +master-bin.000001 5716 Write_rows 1 5750 table_id: # flags: STMT_END_F +master-bin.000001 5750 Table_map 1 5791 table_id: # (test.t1) +master-bin.000001 5791 Write_rows 1 5825 table_id: # flags: STMT_END_F +master-bin.000001 5825 Table_map 1 5866 table_id: # (test.t1) +master-bin.000001 5866 Write_rows 1 5900 table_id: # flags: STMT_END_F +master-bin.000001 5900 Table_map 1 5941 table_id: # (test.t1) +master-bin.000001 5941 Write_rows 1 5975 table_id: # flags: STMT_END_F +master-bin.000001 5975 Table_map 1 6016 table_id: # (test.t1) +master-bin.000001 6016 Write_rows 1 6050 table_id: # flags: STMT_END_F +master-bin.000001 6050 Table_map 1 6091 table_id: # (test.t1) +master-bin.000001 6091 Write_rows 1 6125 table_id: # flags: STMT_END_F +master-bin.000001 6125 Table_map 1 6166 table_id: # (test.t1) +master-bin.000001 6166 Write_rows 1 6200 table_id: # flags: STMT_END_F +master-bin.000001 6200 Table_map 1 6241 table_id: # (test.t1) +master-bin.000001 6241 Write_rows 1 6275 table_id: # flags: STMT_END_F +master-bin.000001 6275 Table_map 1 6316 table_id: # (test.t1) +master-bin.000001 6316 Write_rows 1 6350 table_id: # flags: STMT_END_F +master-bin.000001 6350 Table_map 1 6391 table_id: # (test.t1) +master-bin.000001 6391 Write_rows 1 6425 table_id: # flags: STMT_END_F +master-bin.000001 6425 Table_map 1 6466 table_id: # (test.t1) +master-bin.000001 6466 Write_rows 1 6500 table_id: # flags: STMT_END_F +master-bin.000001 6500 Table_map 1 6541 table_id: # (test.t1) +master-bin.000001 6541 Write_rows 1 6575 table_id: # flags: STMT_END_F +master-bin.000001 6575 Table_map 1 6616 table_id: # (test.t1) +master-bin.000001 6616 Write_rows 1 6650 table_id: # flags: STMT_END_F +master-bin.000001 6650 Table_map 1 6691 table_id: # (test.t1) +master-bin.000001 6691 Write_rows 1 6725 table_id: # flags: STMT_END_F +master-bin.000001 6725 Table_map 1 6766 table_id: # (test.t1) +master-bin.000001 6766 Write_rows 1 6800 table_id: # flags: STMT_END_F +master-bin.000001 6800 Table_map 1 6841 table_id: # (test.t1) +master-bin.000001 6841 Write_rows 1 6875 table_id: # flags: STMT_END_F +master-bin.000001 6875 Table_map 1 6916 table_id: # (test.t1) +master-bin.000001 6916 Write_rows 1 6950 table_id: # flags: STMT_END_F +master-bin.000001 6950 Table_map 1 6991 table_id: # (test.t1) +master-bin.000001 6991 Write_rows 1 7025 table_id: # flags: STMT_END_F +master-bin.000001 7025 Table_map 1 7066 table_id: # (test.t1) +master-bin.000001 7066 Write_rows 1 7100 table_id: # flags: STMT_END_F +master-bin.000001 7100 Table_map 1 7141 table_id: # (test.t1) +master-bin.000001 7141 Write_rows 1 7175 table_id: # flags: STMT_END_F +master-bin.000001 7175 Table_map 1 7216 table_id: # (test.t1) +master-bin.000001 7216 Write_rows 1 7250 table_id: # flags: STMT_END_F +master-bin.000001 7250 Table_map 1 7291 table_id: # (test.t1) +master-bin.000001 7291 Write_rows 1 7325 table_id: # flags: STMT_END_F +master-bin.000001 7325 Table_map 1 7366 table_id: # (test.t1) +master-bin.000001 7366 Write_rows 1 7400 table_id: # flags: STMT_END_F +master-bin.000001 7400 Table_map 1 7441 table_id: # (test.t1) +master-bin.000001 7441 Write_rows 1 7475 table_id: # flags: STMT_END_F +master-bin.000001 7475 Table_map 1 7516 table_id: # (test.t1) +master-bin.000001 7516 Write_rows 1 7550 table_id: # flags: STMT_END_F +master-bin.000001 7550 Table_map 1 7591 table_id: # (test.t1) +master-bin.000001 7591 Write_rows 1 7625 table_id: # flags: STMT_END_F +master-bin.000001 7625 Table_map 1 7666 table_id: # (test.t1) +master-bin.000001 7666 Write_rows 1 7700 table_id: # flags: STMT_END_F +master-bin.000001 7700 Table_map 1 7741 table_id: # (test.t1) +master-bin.000001 7741 Write_rows 1 7775 table_id: # flags: STMT_END_F +master-bin.000001 7775 Table_map 1 7816 table_id: # (test.t1) +master-bin.000001 7816 Write_rows 1 7850 table_id: # flags: STMT_END_F +master-bin.000001 7850 Table_map 1 7891 table_id: # (test.t1) +master-bin.000001 7891 Write_rows 1 7925 table_id: # flags: STMT_END_F +master-bin.000001 7925 Table_map 1 7966 table_id: # (test.t1) +master-bin.000001 7966 Write_rows 1 8000 table_id: # flags: STMT_END_F +master-bin.000001 8000 Table_map 1 8041 table_id: # (test.t1) +master-bin.000001 8041 Write_rows 1 8075 table_id: # flags: STMT_END_F +master-bin.000001 8075 Table_map 1 8116 table_id: # (test.t1) +master-bin.000001 8116 Write_rows 1 8150 table_id: # flags: STMT_END_F +master-bin.000001 8150 Table_map 1 8191 table_id: # (test.t1) +master-bin.000001 8191 Write_rows 1 8225 table_id: # flags: STMT_END_F +master-bin.000001 8225 Table_map 1 8266 table_id: # (test.t1) +master-bin.000001 8266 Write_rows 1 8300 table_id: # flags: STMT_END_F +master-bin.000001 8300 Table_map 1 8341 table_id: # (test.t1) +master-bin.000001 8341 Write_rows 1 8375 table_id: # flags: STMT_END_F +master-bin.000001 8375 Table_map 1 8416 table_id: # (test.t1) +master-bin.000001 8416 Write_rows 1 8450 table_id: # flags: STMT_END_F +master-bin.000001 8450 Table_map 1 8491 table_id: # (test.t1) +master-bin.000001 8491 Write_rows 1 8525 table_id: # flags: STMT_END_F +master-bin.000001 8525 Table_map 1 8566 table_id: # (test.t1) +master-bin.000001 8566 Write_rows 1 8600 table_id: # flags: STMT_END_F +master-bin.000001 8600 Table_map 1 8641 table_id: # (test.t1) +master-bin.000001 8641 Write_rows 1 8675 table_id: # flags: STMT_END_F +master-bin.000001 8675 Table_map 1 8716 table_id: # (test.t1) +master-bin.000001 8716 Write_rows 1 8750 table_id: # flags: STMT_END_F +master-bin.000001 8750 Table_map 1 8791 table_id: # (test.t1) +master-bin.000001 8791 Write_rows 1 8825 table_id: # flags: STMT_END_F +master-bin.000001 8825 Table_map 1 8866 table_id: # (test.t1) +master-bin.000001 8866 Write_rows 1 8900 table_id: # flags: STMT_END_F +master-bin.000001 8900 Table_map 1 8941 table_id: # (test.t1) +master-bin.000001 8941 Write_rows 1 8975 table_id: # flags: STMT_END_F +master-bin.000001 8975 Table_map 1 9016 table_id: # (test.t1) +master-bin.000001 9016 Write_rows 1 9050 table_id: # flags: STMT_END_F +master-bin.000001 9050 Table_map 1 9091 table_id: # (test.t1) +master-bin.000001 9091 Write_rows 1 9125 table_id: # flags: STMT_END_F +master-bin.000001 9125 Table_map 1 9166 table_id: # (test.t1) +master-bin.000001 9166 Write_rows 1 9200 table_id: # flags: STMT_END_F +master-bin.000001 9200 Table_map 1 9241 table_id: # (test.t1) +master-bin.000001 9241 Write_rows 1 9275 table_id: # flags: STMT_END_F +master-bin.000001 9275 Table_map 1 9316 table_id: # (test.t1) +master-bin.000001 9316 Write_rows 1 9350 table_id: # flags: STMT_END_F +master-bin.000001 9350 Table_map 1 9391 table_id: # (test.t1) +master-bin.000001 9391 Write_rows 1 9425 table_id: # flags: STMT_END_F +master-bin.000001 9425 Table_map 1 9466 table_id: # (test.t1) +master-bin.000001 9466 Write_rows 1 9500 table_id: # flags: STMT_END_F +master-bin.000001 9500 Table_map 1 9541 table_id: # (test.t1) +master-bin.000001 9541 Write_rows 1 9575 table_id: # flags: STMT_END_F +master-bin.000001 9575 Table_map 1 9616 table_id: # (test.t1) +master-bin.000001 9616 Write_rows 1 9650 table_id: # flags: STMT_END_F +master-bin.000001 9650 Table_map 1 9691 table_id: # (test.t1) +master-bin.000001 9691 Write_rows 1 9725 table_id: # flags: STMT_END_F +master-bin.000001 9725 Table_map 1 9766 table_id: # (test.t1) +master-bin.000001 9766 Write_rows 1 9800 table_id: # flags: STMT_END_F +master-bin.000001 9800 Table_map 1 9841 table_id: # (test.t1) +master-bin.000001 9841 Write_rows 1 9875 table_id: # flags: STMT_END_F +master-bin.000001 9875 Table_map 1 9916 table_id: # (test.t1) +master-bin.000001 9916 Write_rows 1 9950 table_id: # flags: STMT_END_F +master-bin.000001 9950 Table_map 1 9991 table_id: # (test.t1) +master-bin.000001 9991 Write_rows 1 10025 table_id: # flags: STMT_END_F +master-bin.000001 10025 Table_map 1 10066 table_id: # (test.t1) +master-bin.000001 10066 Write_rows 1 10100 table_id: # flags: STMT_END_F +master-bin.000001 10100 Table_map 1 10141 table_id: # (test.t1) +master-bin.000001 10141 Write_rows 1 10175 table_id: # flags: STMT_END_F +master-bin.000001 10175 Table_map 1 10216 table_id: # (test.t1) +master-bin.000001 10216 Write_rows 1 10250 table_id: # flags: STMT_END_F +master-bin.000001 10250 Table_map 1 10291 table_id: # (test.t1) +master-bin.000001 10291 Write_rows 1 10325 table_id: # flags: STMT_END_F +master-bin.000001 10325 Table_map 1 10366 table_id: # (test.t1) +master-bin.000001 10366 Write_rows 1 10400 table_id: # flags: STMT_END_F +master-bin.000001 10400 Table_map 1 10441 table_id: # (test.t1) +master-bin.000001 10441 Write_rows 1 10475 table_id: # flags: STMT_END_F +master-bin.000001 10475 Table_map 1 10516 table_id: # (test.t1) +master-bin.000001 10516 Write_rows 1 10550 table_id: # flags: STMT_END_F +master-bin.000001 10550 Table_map 1 10591 table_id: # (test.t1) +master-bin.000001 10591 Write_rows 1 10625 table_id: # flags: STMT_END_F +master-bin.000001 10625 Table_map 1 10666 table_id: # (test.t1) +master-bin.000001 10666 Write_rows 1 10700 table_id: # flags: STMT_END_F +master-bin.000001 10700 Table_map 1 10741 table_id: # (test.t1) +master-bin.000001 10741 Write_rows 1 10775 table_id: # flags: STMT_END_F +master-bin.000001 10775 Table_map 1 10816 table_id: # (test.t1) +master-bin.000001 10816 Write_rows 1 10850 table_id: # flags: STMT_END_F +master-bin.000001 10850 Table_map 1 10891 table_id: # (test.t1) +master-bin.000001 10891 Write_rows 1 10925 table_id: # flags: STMT_END_F +master-bin.000001 10925 Table_map 1 10966 table_id: # (test.t1) +master-bin.000001 10966 Write_rows 1 11000 table_id: # flags: STMT_END_F +master-bin.000001 11000 Table_map 1 11041 table_id: # (test.t1) +master-bin.000001 11041 Write_rows 1 11075 table_id: # flags: STMT_END_F +master-bin.000001 11075 Table_map 1 11116 table_id: # (test.t1) +master-bin.000001 11116 Write_rows 1 11150 table_id: # flags: STMT_END_F +master-bin.000001 11150 Table_map 1 11191 table_id: # (test.t1) +master-bin.000001 11191 Write_rows 1 11225 table_id: # flags: STMT_END_F +master-bin.000001 11225 Table_map 1 11266 table_id: # (test.t1) +master-bin.000001 11266 Write_rows 1 11300 table_id: # flags: STMT_END_F +master-bin.000001 11300 Table_map 1 11341 table_id: # (test.t1) +master-bin.000001 11341 Write_rows 1 11375 table_id: # flags: STMT_END_F +master-bin.000001 11375 Table_map 1 11416 table_id: # (test.t1) +master-bin.000001 11416 Write_rows 1 11450 table_id: # flags: STMT_END_F +master-bin.000001 11450 Table_map 1 11491 table_id: # (test.t1) +master-bin.000001 11491 Write_rows 1 11525 table_id: # flags: STMT_END_F +master-bin.000001 11525 Table_map 1 11566 table_id: # (test.t1) +master-bin.000001 11566 Write_rows 1 11600 table_id: # flags: STMT_END_F +master-bin.000001 11600 Table_map 1 11641 table_id: # (test.t1) +master-bin.000001 11641 Write_rows 1 11675 table_id: # flags: STMT_END_F +master-bin.000001 11675 Table_map 1 11716 table_id: # (test.t1) +master-bin.000001 11716 Write_rows 1 11750 table_id: # flags: STMT_END_F +master-bin.000001 11750 Table_map 1 11791 table_id: # (test.t1) +master-bin.000001 11791 Write_rows 1 11825 table_id: # flags: STMT_END_F +master-bin.000001 11825 Table_map 1 11866 table_id: # (test.t1) +master-bin.000001 11866 Write_rows 1 11900 table_id: # flags: STMT_END_F +master-bin.000001 11900 Table_map 1 11941 table_id: # (test.t1) +master-bin.000001 11941 Write_rows 1 11975 table_id: # flags: STMT_END_F +master-bin.000001 11975 Table_map 1 12016 table_id: # (test.t1) +master-bin.000001 12016 Write_rows 1 12050 table_id: # flags: STMT_END_F +master-bin.000001 12050 Table_map 1 12091 table_id: # (test.t1) +master-bin.000001 12091 Write_rows 1 12125 table_id: # flags: STMT_END_F +master-bin.000001 12125 Table_map 1 12166 table_id: # (test.t1) +master-bin.000001 12166 Write_rows 1 12200 table_id: # flags: STMT_END_F +master-bin.000001 12200 Table_map 1 12241 table_id: # (test.t1) +master-bin.000001 12241 Write_rows 1 12275 table_id: # flags: STMT_END_F +master-bin.000001 12275 Table_map 1 12316 table_id: # (test.t1) +master-bin.000001 12316 Write_rows 1 12350 table_id: # flags: STMT_END_F +master-bin.000001 12350 Table_map 1 12391 table_id: # (test.t1) +master-bin.000001 12391 Write_rows 1 12425 table_id: # flags: STMT_END_F +master-bin.000001 12425 Table_map 1 12466 table_id: # (test.t1) +master-bin.000001 12466 Write_rows 1 12500 table_id: # flags: STMT_END_F +master-bin.000001 12500 Table_map 1 12541 table_id: # (test.t1) +master-bin.000001 12541 Write_rows 1 12575 table_id: # flags: STMT_END_F +master-bin.000001 12575 Table_map 1 12616 table_id: # (test.t1) +master-bin.000001 12616 Write_rows 1 12650 table_id: # flags: STMT_END_F +master-bin.000001 12650 Table_map 1 12691 table_id: # (test.t1) +master-bin.000001 12691 Write_rows 1 12725 table_id: # flags: STMT_END_F +master-bin.000001 12725 Table_map 1 12766 table_id: # (test.t1) +master-bin.000001 12766 Write_rows 1 12800 table_id: # flags: STMT_END_F +master-bin.000001 12800 Table_map 1 12841 table_id: # (test.t1) +master-bin.000001 12841 Write_rows 1 12875 table_id: # flags: STMT_END_F +master-bin.000001 12875 Table_map 1 12916 table_id: # (test.t1) +master-bin.000001 12916 Write_rows 1 12950 table_id: # flags: STMT_END_F +master-bin.000001 12950 Table_map 1 12991 table_id: # (test.t1) +master-bin.000001 12991 Write_rows 1 13025 table_id: # flags: STMT_END_F +master-bin.000001 13025 Table_map 1 13066 table_id: # (test.t1) +master-bin.000001 13066 Write_rows 1 13100 table_id: # flags: STMT_END_F +master-bin.000001 13100 Table_map 1 13141 table_id: # (test.t1) +master-bin.000001 13141 Write_rows 1 13175 table_id: # flags: STMT_END_F +master-bin.000001 13175 Table_map 1 13216 table_id: # (test.t1) +master-bin.000001 13216 Write_rows 1 13250 table_id: # flags: STMT_END_F +master-bin.000001 13250 Table_map 1 13291 table_id: # (test.t1) +master-bin.000001 13291 Write_rows 1 13325 table_id: # flags: STMT_END_F +master-bin.000001 13325 Table_map 1 13366 table_id: # (test.t1) +master-bin.000001 13366 Write_rows 1 13400 table_id: # flags: STMT_END_F +master-bin.000001 13400 Table_map 1 13441 table_id: # (test.t1) +master-bin.000001 13441 Write_rows 1 13475 table_id: # flags: STMT_END_F +master-bin.000001 13475 Table_map 1 13516 table_id: # (test.t1) +master-bin.000001 13516 Write_rows 1 13550 table_id: # flags: STMT_END_F +master-bin.000001 13550 Table_map 1 13591 table_id: # (test.t1) +master-bin.000001 13591 Write_rows 1 13625 table_id: # flags: STMT_END_F +master-bin.000001 13625 Table_map 1 13666 table_id: # (test.t1) +master-bin.000001 13666 Write_rows 1 13700 table_id: # flags: STMT_END_F +master-bin.000001 13700 Table_map 1 13741 table_id: # (test.t1) +master-bin.000001 13741 Write_rows 1 13775 table_id: # flags: STMT_END_F +master-bin.000001 13775 Table_map 1 13816 table_id: # (test.t1) +master-bin.000001 13816 Write_rows 1 13850 table_id: # flags: STMT_END_F +master-bin.000001 13850 Table_map 1 13891 table_id: # (test.t1) +master-bin.000001 13891 Write_rows 1 13925 table_id: # flags: STMT_END_F +master-bin.000001 13925 Table_map 1 13966 table_id: # (test.t1) +master-bin.000001 13966 Write_rows 1 14000 table_id: # flags: STMT_END_F +master-bin.000001 14000 Table_map 1 14041 table_id: # (test.t1) +master-bin.000001 14041 Write_rows 1 14075 table_id: # flags: STMT_END_F +master-bin.000001 14075 Table_map 1 14116 table_id: # (test.t1) +master-bin.000001 14116 Write_rows 1 14150 table_id: # flags: STMT_END_F +master-bin.000001 14150 Table_map 1 14191 table_id: # (test.t1) +master-bin.000001 14191 Write_rows 1 14225 table_id: # flags: STMT_END_F +master-bin.000001 14225 Table_map 1 14266 table_id: # (test.t1) +master-bin.000001 14266 Write_rows 1 14300 table_id: # flags: STMT_END_F +master-bin.000001 14300 Table_map 1 14341 table_id: # (test.t1) +master-bin.000001 14341 Write_rows 1 14375 table_id: # flags: STMT_END_F +master-bin.000001 14375 Table_map 1 14416 table_id: # (test.t1) +master-bin.000001 14416 Write_rows 1 14450 table_id: # flags: STMT_END_F +master-bin.000001 14450 Table_map 1 14491 table_id: # (test.t1) +master-bin.000001 14491 Write_rows 1 14525 table_id: # flags: STMT_END_F +master-bin.000001 14525 Table_map 1 14566 table_id: # (test.t1) +master-bin.000001 14566 Write_rows 1 14600 table_id: # flags: STMT_END_F +master-bin.000001 14600 Table_map 1 14641 table_id: # (test.t1) +master-bin.000001 14641 Write_rows 1 14675 table_id: # flags: STMT_END_F +master-bin.000001 14675 Table_map 1 14716 table_id: # (test.t1) +master-bin.000001 14716 Write_rows 1 14750 table_id: # flags: STMT_END_F +master-bin.000001 14750 Table_map 1 14791 table_id: # (test.t1) +master-bin.000001 14791 Write_rows 1 14825 table_id: # flags: STMT_END_F +master-bin.000001 14825 Table_map 1 14866 table_id: # (test.t1) +master-bin.000001 14866 Write_rows 1 14900 table_id: # flags: STMT_END_F +master-bin.000001 14900 Table_map 1 14941 table_id: # (test.t1) +master-bin.000001 14941 Write_rows 1 14975 table_id: # flags: STMT_END_F +master-bin.000001 14975 Table_map 1 15016 table_id: # (test.t1) +master-bin.000001 15016 Write_rows 1 15050 table_id: # flags: STMT_END_F +master-bin.000001 15050 Table_map 1 15091 table_id: # (test.t1) +master-bin.000001 15091 Write_rows 1 15125 table_id: # flags: STMT_END_F +master-bin.000001 15125 Table_map 1 15166 table_id: # (test.t1) +master-bin.000001 15166 Write_rows 1 15200 table_id: # flags: STMT_END_F +master-bin.000001 15200 Table_map 1 15241 table_id: # (test.t1) +master-bin.000001 15241 Write_rows 1 15275 table_id: # flags: STMT_END_F +master-bin.000001 15275 Table_map 1 15316 table_id: # (test.t1) +master-bin.000001 15316 Write_rows 1 15350 table_id: # flags: STMT_END_F +master-bin.000001 15350 Table_map 1 15391 table_id: # (test.t1) +master-bin.000001 15391 Write_rows 1 15425 table_id: # flags: STMT_END_F +master-bin.000001 15425 Table_map 1 15466 table_id: # (test.t1) +master-bin.000001 15466 Write_rows 1 15500 table_id: # flags: STMT_END_F +master-bin.000001 15500 Table_map 1 15541 table_id: # (test.t1) +master-bin.000001 15541 Write_rows 1 15575 table_id: # flags: STMT_END_F +master-bin.000001 15575 Table_map 1 15616 table_id: # (test.t1) +master-bin.000001 15616 Write_rows 1 15650 table_id: # flags: STMT_END_F +master-bin.000001 15650 Table_map 1 15691 table_id: # (test.t1) +master-bin.000001 15691 Write_rows 1 15725 table_id: # flags: STMT_END_F +master-bin.000001 15725 Table_map 1 15766 table_id: # (test.t1) +master-bin.000001 15766 Write_rows 1 15800 table_id: # flags: STMT_END_F +master-bin.000001 15800 Table_map 1 15841 table_id: # (test.t1) +master-bin.000001 15841 Write_rows 1 15875 table_id: # flags: STMT_END_F +master-bin.000001 15875 Table_map 1 15916 table_id: # (test.t1) +master-bin.000001 15916 Write_rows 1 15950 table_id: # flags: STMT_END_F +master-bin.000001 15950 Table_map 1 15991 table_id: # (test.t1) +master-bin.000001 15991 Write_rows 1 16025 table_id: # flags: STMT_END_F +master-bin.000001 16025 Table_map 1 16066 table_id: # (test.t1) +master-bin.000001 16066 Write_rows 1 16100 table_id: # flags: STMT_END_F +master-bin.000001 16100 Table_map 1 16141 table_id: # (test.t1) +master-bin.000001 16141 Write_rows 1 16175 table_id: # flags: STMT_END_F +master-bin.000001 16175 Table_map 1 16216 table_id: # (test.t1) +master-bin.000001 16216 Write_rows 1 16250 table_id: # flags: STMT_END_F +master-bin.000001 16250 Table_map 1 16291 table_id: # (test.t1) +master-bin.000001 16291 Write_rows 1 16325 table_id: # flags: STMT_END_F +master-bin.000001 16325 Table_map 1 16366 table_id: # (test.t1) +master-bin.000001 16366 Write_rows 1 16400 table_id: # flags: STMT_END_F +master-bin.000001 16400 Table_map 1 16441 table_id: # (test.t1) +master-bin.000001 16441 Write_rows 1 16475 table_id: # flags: STMT_END_F +master-bin.000001 16475 Table_map 1 16516 table_id: # (test.t1) +master-bin.000001 16516 Write_rows 1 16550 table_id: # flags: STMT_END_F +master-bin.000001 16550 Table_map 1 16591 table_id: # (test.t1) +master-bin.000001 16591 Write_rows 1 16625 table_id: # flags: STMT_END_F +master-bin.000001 16625 Table_map 1 16666 table_id: # (test.t1) +master-bin.000001 16666 Write_rows 1 16700 table_id: # flags: STMT_END_F +master-bin.000001 16700 Table_map 1 16741 table_id: # (test.t1) +master-bin.000001 16741 Write_rows 1 16775 table_id: # flags: STMT_END_F +master-bin.000001 16775 Table_map 1 16816 table_id: # (test.t1) +master-bin.000001 16816 Write_rows 1 16850 table_id: # flags: STMT_END_F +master-bin.000001 16850 Table_map 1 16891 table_id: # (test.t1) +master-bin.000001 16891 Write_rows 1 16925 table_id: # flags: STMT_END_F +master-bin.000001 16925 Table_map 1 16966 table_id: # (test.t1) +master-bin.000001 16966 Write_rows 1 17000 table_id: # flags: STMT_END_F +master-bin.000001 17000 Table_map 1 17041 table_id: # (test.t1) +master-bin.000001 17041 Write_rows 1 17075 table_id: # flags: STMT_END_F +master-bin.000001 17075 Table_map 1 17116 table_id: # (test.t1) +master-bin.000001 17116 Write_rows 1 17150 table_id: # flags: STMT_END_F +master-bin.000001 17150 Table_map 1 17191 table_id: # (test.t1) +master-bin.000001 17191 Write_rows 1 17225 table_id: # flags: STMT_END_F +master-bin.000001 17225 Table_map 1 17266 table_id: # (test.t1) +master-bin.000001 17266 Write_rows 1 17300 table_id: # flags: STMT_END_F +master-bin.000001 17300 Table_map 1 17341 table_id: # (test.t1) +master-bin.000001 17341 Write_rows 1 17375 table_id: # flags: STMT_END_F +master-bin.000001 17375 Table_map 1 17416 table_id: # (test.t1) +master-bin.000001 17416 Write_rows 1 17450 table_id: # flags: STMT_END_F +master-bin.000001 17450 Table_map 1 17491 table_id: # (test.t1) +master-bin.000001 17491 Write_rows 1 17525 table_id: # flags: STMT_END_F +master-bin.000001 17525 Table_map 1 17566 table_id: # (test.t1) +master-bin.000001 17566 Write_rows 1 17600 table_id: # flags: STMT_END_F +master-bin.000001 17600 Table_map 1 17641 table_id: # (test.t1) +master-bin.000001 17641 Write_rows 1 17675 table_id: # flags: STMT_END_F +master-bin.000001 17675 Table_map 1 17716 table_id: # (test.t1) +master-bin.000001 17716 Write_rows 1 17750 table_id: # flags: STMT_END_F +master-bin.000001 17750 Table_map 1 17791 table_id: # (test.t1) +master-bin.000001 17791 Write_rows 1 17825 table_id: # flags: STMT_END_F +master-bin.000001 17825 Table_map 1 17866 table_id: # (test.t1) +master-bin.000001 17866 Write_rows 1 17900 table_id: # flags: STMT_END_F +master-bin.000001 17900 Table_map 1 17941 table_id: # (test.t1) +master-bin.000001 17941 Write_rows 1 17975 table_id: # flags: STMT_END_F +master-bin.000001 17975 Table_map 1 18016 table_id: # (test.t1) +master-bin.000001 18016 Write_rows 1 18050 table_id: # flags: STMT_END_F +master-bin.000001 18050 Table_map 1 18091 table_id: # (test.t1) +master-bin.000001 18091 Write_rows 1 18125 table_id: # flags: STMT_END_F +master-bin.000001 18125 Table_map 1 18166 table_id: # (test.t1) +master-bin.000001 18166 Write_rows 1 18200 table_id: # flags: STMT_END_F +master-bin.000001 18200 Table_map 1 18241 table_id: # (test.t1) +master-bin.000001 18241 Write_rows 1 18275 table_id: # flags: STMT_END_F +master-bin.000001 18275 Table_map 1 18316 table_id: # (test.t1) +master-bin.000001 18316 Write_rows 1 18350 table_id: # flags: STMT_END_F +master-bin.000001 18350 Table_map 1 18391 table_id: # (test.t1) +master-bin.000001 18391 Write_rows 1 18425 table_id: # flags: STMT_END_F +master-bin.000001 18425 Table_map 1 18466 table_id: # (test.t1) +master-bin.000001 18466 Write_rows 1 18500 table_id: # flags: STMT_END_F +master-bin.000001 18500 Table_map 1 18541 table_id: # (test.t1) +master-bin.000001 18541 Write_rows 1 18575 table_id: # flags: STMT_END_F +master-bin.000001 18575 Table_map 1 18616 table_id: # (test.t1) +master-bin.000001 18616 Write_rows 1 18650 table_id: # flags: STMT_END_F +master-bin.000001 18650 Table_map 1 18691 table_id: # (test.t1) +master-bin.000001 18691 Write_rows 1 18725 table_id: # flags: STMT_END_F +master-bin.000001 18725 Table_map 1 18766 table_id: # (test.t1) +master-bin.000001 18766 Write_rows 1 18800 table_id: # flags: STMT_END_F +master-bin.000001 18800 Table_map 1 18841 table_id: # (test.t1) +master-bin.000001 18841 Write_rows 1 18875 table_id: # flags: STMT_END_F +master-bin.000001 18875 Table_map 1 18916 table_id: # (test.t1) +master-bin.000001 18916 Write_rows 1 18950 table_id: # flags: STMT_END_F +master-bin.000001 18950 Table_map 1 18991 table_id: # (test.t1) +master-bin.000001 18991 Write_rows 1 19025 table_id: # flags: STMT_END_F +master-bin.000001 19025 Table_map 1 19066 table_id: # (test.t1) +master-bin.000001 19066 Write_rows 1 19100 table_id: # flags: STMT_END_F +master-bin.000001 19100 Table_map 1 19141 table_id: # (test.t1) +master-bin.000001 19141 Write_rows 1 19175 table_id: # flags: STMT_END_F +master-bin.000001 19175 Table_map 1 19216 table_id: # (test.t1) +master-bin.000001 19216 Write_rows 1 19250 table_id: # flags: STMT_END_F +master-bin.000001 19250 Table_map 1 19291 table_id: # (test.t1) +master-bin.000001 19291 Write_rows 1 19325 table_id: # flags: STMT_END_F +master-bin.000001 19325 Table_map 1 19366 table_id: # (test.t1) +master-bin.000001 19366 Write_rows 1 19400 table_id: # flags: STMT_END_F +master-bin.000001 19400 Table_map 1 19441 table_id: # (test.t1) +master-bin.000001 19441 Write_rows 1 19475 table_id: # flags: STMT_END_F +master-bin.000001 19475 Table_map 1 19516 table_id: # (test.t1) +master-bin.000001 19516 Write_rows 1 19550 table_id: # flags: STMT_END_F +master-bin.000001 19550 Table_map 1 19591 table_id: # (test.t1) +master-bin.000001 19591 Write_rows 1 19625 table_id: # flags: STMT_END_F +master-bin.000001 19625 Table_map 1 19666 table_id: # (test.t1) +master-bin.000001 19666 Write_rows 1 19700 table_id: # flags: STMT_END_F +master-bin.000001 19700 Table_map 1 19741 table_id: # (test.t1) +master-bin.000001 19741 Write_rows 1 19775 table_id: # flags: STMT_END_F +master-bin.000001 19775 Table_map 1 19816 table_id: # (test.t1) +master-bin.000001 19816 Write_rows 1 19850 table_id: # flags: STMT_END_F +master-bin.000001 19850 Table_map 1 19891 table_id: # (test.t1) +master-bin.000001 19891 Write_rows 1 19925 table_id: # flags: STMT_END_F +master-bin.000001 19925 Table_map 1 19966 table_id: # (test.t1) +master-bin.000001 19966 Write_rows 1 20000 table_id: # flags: STMT_END_F +master-bin.000001 20000 Table_map 1 20041 table_id: # (test.t1) +master-bin.000001 20041 Write_rows 1 20075 table_id: # flags: STMT_END_F +master-bin.000001 20075 Table_map 1 20116 table_id: # (test.t1) +master-bin.000001 20116 Write_rows 1 20150 table_id: # flags: STMT_END_F +master-bin.000001 20150 Table_map 1 20191 table_id: # (test.t1) +master-bin.000001 20191 Write_rows 1 20225 table_id: # flags: STMT_END_F +master-bin.000001 20225 Table_map 1 20266 table_id: # (test.t1) +master-bin.000001 20266 Write_rows 1 20300 table_id: # flags: STMT_END_F +master-bin.000001 20300 Table_map 1 20341 table_id: # (test.t1) +master-bin.000001 20341 Write_rows 1 20375 table_id: # flags: STMT_END_F +master-bin.000001 20375 Table_map 1 20416 table_id: # (test.t1) +master-bin.000001 20416 Write_rows 1 20450 table_id: # flags: STMT_END_F +master-bin.000001 20450 Table_map 1 20491 table_id: # (test.t1) +master-bin.000001 20491 Write_rows 1 20525 table_id: # flags: STMT_END_F +master-bin.000001 20525 Table_map 1 20566 table_id: # (test.t1) +master-bin.000001 20566 Write_rows 1 20600 table_id: # flags: STMT_END_F +master-bin.000001 20600 Table_map 1 20641 table_id: # (test.t1) +master-bin.000001 20641 Write_rows 1 20675 table_id: # flags: STMT_END_F +master-bin.000001 20675 Table_map 1 20716 table_id: # (test.t1) +master-bin.000001 20716 Write_rows 1 20750 table_id: # flags: STMT_END_F +master-bin.000001 20750 Table_map 1 20791 table_id: # (test.t1) +master-bin.000001 20791 Write_rows 1 20825 table_id: # flags: STMT_END_F +master-bin.000001 20825 Table_map 1 20866 table_id: # (test.t1) +master-bin.000001 20866 Write_rows 1 20900 table_id: # flags: STMT_END_F +master-bin.000001 20900 Table_map 1 20941 table_id: # (test.t1) +master-bin.000001 20941 Write_rows 1 20975 table_id: # flags: STMT_END_F +master-bin.000001 20975 Table_map 1 21016 table_id: # (test.t1) +master-bin.000001 21016 Write_rows 1 21050 table_id: # flags: STMT_END_F +master-bin.000001 21050 Table_map 1 21091 table_id: # (test.t1) +master-bin.000001 21091 Write_rows 1 21125 table_id: # flags: STMT_END_F +master-bin.000001 21125 Table_map 1 21166 table_id: # (test.t1) +master-bin.000001 21166 Write_rows 1 21200 table_id: # flags: STMT_END_F +master-bin.000001 21200 Table_map 1 21241 table_id: # (test.t1) +master-bin.000001 21241 Write_rows 1 21275 table_id: # flags: STMT_END_F +master-bin.000001 21275 Table_map 1 21316 table_id: # (test.t1) +master-bin.000001 21316 Write_rows 1 21350 table_id: # flags: STMT_END_F +master-bin.000001 21350 Table_map 1 21391 table_id: # (test.t1) +master-bin.000001 21391 Write_rows 1 21425 table_id: # flags: STMT_END_F +master-bin.000001 21425 Table_map 1 21466 table_id: # (test.t1) +master-bin.000001 21466 Write_rows 1 21500 table_id: # flags: STMT_END_F +master-bin.000001 21500 Table_map 1 21541 table_id: # (test.t1) +master-bin.000001 21541 Write_rows 1 21575 table_id: # flags: STMT_END_F +master-bin.000001 21575 Table_map 1 21616 table_id: # (test.t1) +master-bin.000001 21616 Write_rows 1 21650 table_id: # flags: STMT_END_F +master-bin.000001 21650 Table_map 1 21691 table_id: # (test.t1) +master-bin.000001 21691 Write_rows 1 21725 table_id: # flags: STMT_END_F +master-bin.000001 21725 Table_map 1 21766 table_id: # (test.t1) +master-bin.000001 21766 Write_rows 1 21800 table_id: # flags: STMT_END_F +master-bin.000001 21800 Table_map 1 21841 table_id: # (test.t1) +master-bin.000001 21841 Write_rows 1 21875 table_id: # flags: STMT_END_F +master-bin.000001 21875 Table_map 1 21916 table_id: # (test.t1) +master-bin.000001 21916 Write_rows 1 21950 table_id: # flags: STMT_END_F +master-bin.000001 21950 Table_map 1 21991 table_id: # (test.t1) +master-bin.000001 21991 Write_rows 1 22025 table_id: # flags: STMT_END_F +master-bin.000001 22025 Table_map 1 22066 table_id: # (test.t1) +master-bin.000001 22066 Write_rows 1 22100 table_id: # flags: STMT_END_F +master-bin.000001 22100 Table_map 1 22141 table_id: # (test.t1) +master-bin.000001 22141 Write_rows 1 22175 table_id: # flags: STMT_END_F +master-bin.000001 22175 Table_map 1 22216 table_id: # (test.t1) +master-bin.000001 22216 Write_rows 1 22250 table_id: # flags: STMT_END_F +master-bin.000001 22250 Table_map 1 22291 table_id: # (test.t1) +master-bin.000001 22291 Write_rows 1 22325 table_id: # flags: STMT_END_F +master-bin.000001 22325 Table_map 1 22366 table_id: # (test.t1) +master-bin.000001 22366 Write_rows 1 22400 table_id: # flags: STMT_END_F +master-bin.000001 22400 Table_map 1 22441 table_id: # (test.t1) +master-bin.000001 22441 Write_rows 1 22475 table_id: # flags: STMT_END_F +master-bin.000001 22475 Table_map 1 22516 table_id: # (test.t1) +master-bin.000001 22516 Write_rows 1 22550 table_id: # flags: STMT_END_F +master-bin.000001 22550 Table_map 1 22591 table_id: # (test.t1) +master-bin.000001 22591 Write_rows 1 22625 table_id: # flags: STMT_END_F +master-bin.000001 22625 Table_map 1 22666 table_id: # (test.t1) +master-bin.000001 22666 Write_rows 1 22700 table_id: # flags: STMT_END_F +master-bin.000001 22700 Table_map 1 22741 table_id: # (test.t1) +master-bin.000001 22741 Write_rows 1 22775 table_id: # flags: STMT_END_F +master-bin.000001 22775 Table_map 1 22816 table_id: # (test.t1) +master-bin.000001 22816 Write_rows 1 22850 table_id: # flags: STMT_END_F +master-bin.000001 22850 Table_map 1 22891 table_id: # (test.t1) +master-bin.000001 22891 Write_rows 1 22925 table_id: # flags: STMT_END_F +master-bin.000001 22925 Table_map 1 22966 table_id: # (test.t1) +master-bin.000001 22966 Write_rows 1 23000 table_id: # flags: STMT_END_F +master-bin.000001 23000 Table_map 1 23041 table_id: # (test.t1) +master-bin.000001 23041 Write_rows 1 23075 table_id: # flags: STMT_END_F +master-bin.000001 23075 Table_map 1 23116 table_id: # (test.t1) +master-bin.000001 23116 Write_rows 1 23150 table_id: # flags: STMT_END_F +master-bin.000001 23150 Table_map 1 23191 table_id: # (test.t1) +master-bin.000001 23191 Write_rows 1 23225 table_id: # flags: STMT_END_F +master-bin.000001 23225 Table_map 1 23266 table_id: # (test.t1) +master-bin.000001 23266 Write_rows 1 23300 table_id: # flags: STMT_END_F +master-bin.000001 23300 Table_map 1 23341 table_id: # (test.t1) +master-bin.000001 23341 Write_rows 1 23375 table_id: # flags: STMT_END_F +master-bin.000001 23375 Table_map 1 23416 table_id: # (test.t1) +master-bin.000001 23416 Write_rows 1 23450 table_id: # flags: STMT_END_F +master-bin.000001 23450 Table_map 1 23491 table_id: # (test.t1) +master-bin.000001 23491 Write_rows 1 23525 table_id: # flags: STMT_END_F +master-bin.000001 23525 Table_map 1 23566 table_id: # (test.t1) +master-bin.000001 23566 Write_rows 1 23600 table_id: # flags: STMT_END_F +master-bin.000001 23600 Table_map 1 23641 table_id: # (test.t1) +master-bin.000001 23641 Write_rows 1 23675 table_id: # flags: STMT_END_F +master-bin.000001 23675 Table_map 1 23716 table_id: # (test.t1) +master-bin.000001 23716 Write_rows 1 23750 table_id: # flags: STMT_END_F +master-bin.000001 23750 Table_map 1 23791 table_id: # (test.t1) +master-bin.000001 23791 Write_rows 1 23825 table_id: # flags: STMT_END_F +master-bin.000001 23825 Table_map 1 23866 table_id: # (test.t1) +master-bin.000001 23866 Write_rows 1 23900 table_id: # flags: STMT_END_F +master-bin.000001 23900 Table_map 1 23941 table_id: # (test.t1) +master-bin.000001 23941 Write_rows 1 23975 table_id: # flags: STMT_END_F +master-bin.000001 23975 Table_map 1 24016 table_id: # (test.t1) +master-bin.000001 24016 Write_rows 1 24050 table_id: # flags: STMT_END_F +master-bin.000001 24050 Table_map 1 24091 table_id: # (test.t1) +master-bin.000001 24091 Write_rows 1 24125 table_id: # flags: STMT_END_F +master-bin.000001 24125 Table_map 1 24166 table_id: # (test.t1) +master-bin.000001 24166 Write_rows 1 24200 table_id: # flags: STMT_END_F +master-bin.000001 24200 Table_map 1 24241 table_id: # (test.t1) +master-bin.000001 24241 Write_rows 1 24275 table_id: # flags: STMT_END_F +master-bin.000001 24275 Table_map 1 24316 table_id: # (test.t1) +master-bin.000001 24316 Write_rows 1 24350 table_id: # flags: STMT_END_F +master-bin.000001 24350 Table_map 1 24391 table_id: # (test.t1) +master-bin.000001 24391 Write_rows 1 24425 table_id: # flags: STMT_END_F +master-bin.000001 24425 Table_map 1 24466 table_id: # (test.t1) +master-bin.000001 24466 Write_rows 1 24500 table_id: # flags: STMT_END_F +master-bin.000001 24500 Table_map 1 24541 table_id: # (test.t1) +master-bin.000001 24541 Write_rows 1 24575 table_id: # flags: STMT_END_F +master-bin.000001 24575 Table_map 1 24616 table_id: # (test.t1) +master-bin.000001 24616 Write_rows 1 24650 table_id: # flags: STMT_END_F +master-bin.000001 24650 Table_map 1 24691 table_id: # (test.t1) +master-bin.000001 24691 Write_rows 1 24725 table_id: # flags: STMT_END_F +master-bin.000001 24725 Table_map 1 24766 table_id: # (test.t1) +master-bin.000001 24766 Write_rows 1 24800 table_id: # flags: STMT_END_F +master-bin.000001 24800 Table_map 1 24841 table_id: # (test.t1) +master-bin.000001 24841 Write_rows 1 24875 table_id: # flags: STMT_END_F +master-bin.000001 24875 Table_map 1 24916 table_id: # (test.t1) +master-bin.000001 24916 Write_rows 1 24950 table_id: # flags: STMT_END_F +master-bin.000001 24950 Table_map 1 24991 table_id: # (test.t1) +master-bin.000001 24991 Write_rows 1 25025 table_id: # flags: STMT_END_F +master-bin.000001 25025 Table_map 1 25066 table_id: # (test.t1) +master-bin.000001 25066 Write_rows 1 25100 table_id: # flags: STMT_END_F +master-bin.000001 25100 Table_map 1 25141 table_id: # (test.t1) +master-bin.000001 25141 Write_rows 1 25175 table_id: # flags: STMT_END_F +master-bin.000001 25175 Table_map 1 25216 table_id: # (test.t1) +master-bin.000001 25216 Write_rows 1 25250 table_id: # flags: STMT_END_F +master-bin.000001 25250 Table_map 1 25291 table_id: # (test.t1) +master-bin.000001 25291 Write_rows 1 25325 table_id: # flags: STMT_END_F +master-bin.000001 25325 Table_map 1 25366 table_id: # (test.t1) +master-bin.000001 25366 Write_rows 1 25400 table_id: # flags: STMT_END_F +master-bin.000001 25400 Table_map 1 25441 table_id: # (test.t1) +master-bin.000001 25441 Write_rows 1 25475 table_id: # flags: STMT_END_F +master-bin.000001 25475 Table_map 1 25516 table_id: # (test.t1) +master-bin.000001 25516 Write_rows 1 25550 table_id: # flags: STMT_END_F +master-bin.000001 25550 Table_map 1 25591 table_id: # (test.t1) +master-bin.000001 25591 Write_rows 1 25625 table_id: # flags: STMT_END_F +master-bin.000001 25625 Table_map 1 25666 table_id: # (test.t1) +master-bin.000001 25666 Write_rows 1 25700 table_id: # flags: STMT_END_F +master-bin.000001 25700 Table_map 1 25741 table_id: # (test.t1) +master-bin.000001 25741 Write_rows 1 25775 table_id: # flags: STMT_END_F +master-bin.000001 25775 Table_map 1 25816 table_id: # (test.t1) +master-bin.000001 25816 Write_rows 1 25850 table_id: # flags: STMT_END_F +master-bin.000001 25850 Table_map 1 25891 table_id: # (test.t1) +master-bin.000001 25891 Write_rows 1 25925 table_id: # flags: STMT_END_F +master-bin.000001 25925 Table_map 1 25966 table_id: # (test.t1) +master-bin.000001 25966 Write_rows 1 26000 table_id: # flags: STMT_END_F +master-bin.000001 26000 Table_map 1 26041 table_id: # (test.t1) +master-bin.000001 26041 Write_rows 1 26075 table_id: # flags: STMT_END_F +master-bin.000001 26075 Table_map 1 26116 table_id: # (test.t1) +master-bin.000001 26116 Write_rows 1 26150 table_id: # flags: STMT_END_F +master-bin.000001 26150 Table_map 1 26191 table_id: # (test.t1) +master-bin.000001 26191 Write_rows 1 26225 table_id: # flags: STMT_END_F +master-bin.000001 26225 Table_map 1 26266 table_id: # (test.t1) +master-bin.000001 26266 Write_rows 1 26300 table_id: # flags: STMT_END_F +master-bin.000001 26300 Table_map 1 26341 table_id: # (test.t1) +master-bin.000001 26341 Write_rows 1 26375 table_id: # flags: STMT_END_F +master-bin.000001 26375 Table_map 1 26416 table_id: # (test.t1) +master-bin.000001 26416 Write_rows 1 26450 table_id: # flags: STMT_END_F +master-bin.000001 26450 Table_map 1 26491 table_id: # (test.t1) +master-bin.000001 26491 Write_rows 1 26525 table_id: # flags: STMT_END_F +master-bin.000001 26525 Table_map 1 26566 table_id: # (test.t1) +master-bin.000001 26566 Write_rows 1 26600 table_id: # flags: STMT_END_F +master-bin.000001 26600 Table_map 1 26641 table_id: # (test.t1) +master-bin.000001 26641 Write_rows 1 26675 table_id: # flags: STMT_END_F +master-bin.000001 26675 Table_map 1 26716 table_id: # (test.t1) +master-bin.000001 26716 Write_rows 1 26750 table_id: # flags: STMT_END_F +master-bin.000001 26750 Table_map 1 26791 table_id: # (test.t1) +master-bin.000001 26791 Write_rows 1 26825 table_id: # flags: STMT_END_F +master-bin.000001 26825 Table_map 1 26866 table_id: # (test.t1) +master-bin.000001 26866 Write_rows 1 26900 table_id: # flags: STMT_END_F +master-bin.000001 26900 Table_map 1 26941 table_id: # (test.t1) +master-bin.000001 26941 Write_rows 1 26975 table_id: # flags: STMT_END_F +master-bin.000001 26975 Table_map 1 27016 table_id: # (test.t1) +master-bin.000001 27016 Write_rows 1 27050 table_id: # flags: STMT_END_F +master-bin.000001 27050 Table_map 1 27091 table_id: # (test.t1) +master-bin.000001 27091 Write_rows 1 27125 table_id: # flags: STMT_END_F +master-bin.000001 27125 Table_map 1 27166 table_id: # (test.t1) +master-bin.000001 27166 Write_rows 1 27200 table_id: # flags: STMT_END_F +master-bin.000001 27200 Table_map 1 27241 table_id: # (test.t1) +master-bin.000001 27241 Write_rows 1 27275 table_id: # flags: STMT_END_F +master-bin.000001 27275 Table_map 1 27316 table_id: # (test.t1) +master-bin.000001 27316 Write_rows 1 27350 table_id: # flags: STMT_END_F +master-bin.000001 27350 Table_map 1 27391 table_id: # (test.t1) +master-bin.000001 27391 Write_rows 1 27425 table_id: # flags: STMT_END_F +master-bin.000001 27425 Table_map 1 27466 table_id: # (test.t1) +master-bin.000001 27466 Write_rows 1 27500 table_id: # flags: STMT_END_F +master-bin.000001 27500 Table_map 1 27541 table_id: # (test.t1) +master-bin.000001 27541 Write_rows 1 27575 table_id: # flags: STMT_END_F +master-bin.000001 27575 Table_map 1 27616 table_id: # (test.t1) +master-bin.000001 27616 Write_rows 1 27650 table_id: # flags: STMT_END_F +master-bin.000001 27650 Table_map 1 27691 table_id: # (test.t1) +master-bin.000001 27691 Write_rows 1 27725 table_id: # flags: STMT_END_F +master-bin.000001 27725 Table_map 1 27766 table_id: # (test.t1) +master-bin.000001 27766 Write_rows 1 27800 table_id: # flags: STMT_END_F +master-bin.000001 27800 Table_map 1 27841 table_id: # (test.t1) +master-bin.000001 27841 Write_rows 1 27875 table_id: # flags: STMT_END_F +master-bin.000001 27875 Table_map 1 27916 table_id: # (test.t1) +master-bin.000001 27916 Write_rows 1 27950 table_id: # flags: STMT_END_F +master-bin.000001 27950 Table_map 1 27991 table_id: # (test.t1) +master-bin.000001 27991 Write_rows 1 28025 table_id: # flags: STMT_END_F +master-bin.000001 28025 Table_map 1 28066 table_id: # (test.t1) +master-bin.000001 28066 Write_rows 1 28100 table_id: # flags: STMT_END_F +master-bin.000001 28100 Table_map 1 28141 table_id: # (test.t1) +master-bin.000001 28141 Write_rows 1 28175 table_id: # flags: STMT_END_F +master-bin.000001 28175 Table_map 1 28216 table_id: # (test.t1) +master-bin.000001 28216 Write_rows 1 28250 table_id: # flags: STMT_END_F +master-bin.000001 28250 Table_map 1 28291 table_id: # (test.t1) +master-bin.000001 28291 Write_rows 1 28325 table_id: # flags: STMT_END_F +master-bin.000001 28325 Table_map 1 28366 table_id: # (test.t1) +master-bin.000001 28366 Write_rows 1 28400 table_id: # flags: STMT_END_F +master-bin.000001 28400 Table_map 1 28441 table_id: # (test.t1) +master-bin.000001 28441 Write_rows 1 28475 table_id: # flags: STMT_END_F +master-bin.000001 28475 Table_map 1 28516 table_id: # (test.t1) +master-bin.000001 28516 Write_rows 1 28550 table_id: # flags: STMT_END_F +master-bin.000001 28550 Table_map 1 28591 table_id: # (test.t1) +master-bin.000001 28591 Write_rows 1 28625 table_id: # flags: STMT_END_F +master-bin.000001 28625 Table_map 1 28666 table_id: # (test.t1) +master-bin.000001 28666 Write_rows 1 28700 table_id: # flags: STMT_END_F +master-bin.000001 28700 Table_map 1 28741 table_id: # (test.t1) +master-bin.000001 28741 Write_rows 1 28775 table_id: # flags: STMT_END_F +master-bin.000001 28775 Table_map 1 28816 table_id: # (test.t1) +master-bin.000001 28816 Write_rows 1 28850 table_id: # flags: STMT_END_F +master-bin.000001 28850 Table_map 1 28891 table_id: # (test.t1) +master-bin.000001 28891 Write_rows 1 28925 table_id: # flags: STMT_END_F +master-bin.000001 28925 Table_map 1 28966 table_id: # (test.t1) +master-bin.000001 28966 Write_rows 1 29000 table_id: # flags: STMT_END_F +master-bin.000001 29000 Table_map 1 29041 table_id: # (test.t1) +master-bin.000001 29041 Write_rows 1 29075 table_id: # flags: STMT_END_F +master-bin.000001 29075 Table_map 1 29116 table_id: # (test.t1) +master-bin.000001 29116 Write_rows 1 29150 table_id: # flags: STMT_END_F +master-bin.000001 29150 Table_map 1 29191 table_id: # (test.t1) +master-bin.000001 29191 Write_rows 1 29225 table_id: # flags: STMT_END_F +master-bin.000001 29225 Table_map 1 29266 table_id: # (test.t1) +master-bin.000001 29266 Write_rows 1 29300 table_id: # flags: STMT_END_F +master-bin.000001 29300 Table_map 1 29341 table_id: # (test.t1) +master-bin.000001 29341 Write_rows 1 29375 table_id: # flags: STMT_END_F +master-bin.000001 29375 Table_map 1 29416 table_id: # (test.t1) +master-bin.000001 29416 Write_rows 1 29450 table_id: # flags: STMT_END_F +master-bin.000001 29450 Table_map 1 29491 table_id: # (test.t1) +master-bin.000001 29491 Write_rows 1 29525 table_id: # flags: STMT_END_F +master-bin.000001 29525 Table_map 1 29566 table_id: # (test.t1) +master-bin.000001 29566 Write_rows 1 29600 table_id: # flags: STMT_END_F +master-bin.000001 29600 Table_map 1 29641 table_id: # (test.t1) +master-bin.000001 29641 Write_rows 1 29675 table_id: # flags: STMT_END_F +master-bin.000001 29675 Table_map 1 29716 table_id: # (test.t1) +master-bin.000001 29716 Write_rows 1 29750 table_id: # flags: STMT_END_F +master-bin.000001 29750 Table_map 1 29791 table_id: # (test.t1) +master-bin.000001 29791 Write_rows 1 29825 table_id: # flags: STMT_END_F +master-bin.000001 29825 Table_map 1 29866 table_id: # (test.t1) +master-bin.000001 29866 Write_rows 1 29900 table_id: # flags: STMT_END_F +master-bin.000001 29900 Table_map 1 29941 table_id: # (test.t1) +master-bin.000001 29941 Write_rows 1 29975 table_id: # flags: STMT_END_F +master-bin.000001 29975 Table_map 1 30016 table_id: # (test.t1) +master-bin.000001 30016 Write_rows 1 30050 table_id: # flags: STMT_END_F +master-bin.000001 30050 Table_map 1 30091 table_id: # (test.t1) +master-bin.000001 30091 Write_rows 1 30125 table_id: # flags: STMT_END_F +master-bin.000001 30125 Table_map 1 30166 table_id: # (test.t1) +master-bin.000001 30166 Write_rows 1 30200 table_id: # flags: STMT_END_F +master-bin.000001 30200 Table_map 1 30241 table_id: # (test.t1) +master-bin.000001 30241 Write_rows 1 30275 table_id: # flags: STMT_END_F +master-bin.000001 30275 Xid 1 30302 COMMIT /* XID */ +master-bin.000001 30302 Rotate 1 30346 master-bin.000002;pos=4 drop table t1; set global binlog_cache_size=@bcs; set session autocommit = @ac; @@ -1289,14 +1306,14 @@ drop table if exists t3; create table t3 (a int(11) NOT NULL AUTO_INCREMENT, b text, PRIMARY KEY (a) ) engine=innodb; show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 346 +master-bin.000001 347 insert into t3(b) values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); insert into t3(b) values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); insert into t3(b) values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); insert into t3(b) values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); show master status /* must show new binlog index after rotating */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000002 106 +master-bin.000002 107 drop table t3; # # Bug #45998: database crashes when running "create as select" diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index d05d3ccdb7a..9df4164b138 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -36,7 +36,7 @@ create table t1 (n int) engine=innodb; begin; commit; drop table t1; -show binlog events in 'master-bin.000001' from 106; +show binlog events in 'master-bin.000001' from 107; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1 (n int) engine=innodb master-bin.000001 # Query 1 # BEGIN @@ -142,7 +142,7 @@ master-bin.000001 # Query 1 # use `test`; insert into t1 values(2 + 4) master-bin.000001 # Query 1 # use `test`; insert into t1 values(1 + 4) master-bin.000001 # Xid 1 # COMMIT /* xid= */ master-bin.000001 # Rotate 1 # master-bin.000002;pos=4 -show binlog events in 'master-bin.000002' from 106; +show binlog events in 'master-bin.000002' from 107; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000002 # Query 1 # use `test`; drop table t1 set @ac = @@autocommit; @@ -764,14 +764,14 @@ drop table if exists t3; create table t3 (a int(11) NOT NULL AUTO_INCREMENT, b text, PRIMARY KEY (a) ) engine=innodb; show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 346 +master-bin.000001 347 insert into t3(b) values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); insert into t3(b) values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); insert into t3(b) values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); insert into t3(b) values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); show master status /* must show new binlog index after rotating */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000002 106 +master-bin.000002 107 drop table t3; # # Bug #45998: database crashes when running "create as select" diff --git a/mysql-test/suite/binlog/t/binlog_innodb.test b/mysql-test/suite/binlog/t/binlog_innodb.test index f84fd65226a..4469fa6224c 100644 --- a/mysql-test/suite/binlog/t/binlog_innodb.test +++ b/mysql-test/suite/binlog/t/binlog_innodb.test @@ -155,7 +155,8 @@ reset master; UPDATE t2,t1 SET t2.a=t1.a+2; # check select * from t2 /* must be (3,1), (4,4) */; -show master status /* there must no UPDATE in binlog */; +--echo there must no UPDATE in binlog +source include/show_master_status.inc; # B. testing multi_update::send_error() execution branch delete from t1; @@ -165,7 +166,8 @@ insert into t2 values (1,2),(3,4),(4,4); reset master; --error ER_DUP_ENTRY UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; -show master status /* there must be no UPDATE query event */; +--echo there must no UPDATE in binlog +source include/show_master_status.inc; # cleanup bug#27716 drop table t1, t2; diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test index 9b30ec4a0db..d4aa91140cf 100644 --- a/mysql-test/suite/binlog/t/binlog_killed.test +++ b/mysql-test/suite/binlog/t/binlog_killed.test @@ -51,7 +51,7 @@ reap; let $rows= `select count(*) from t2 /* must be 2 or 0 */`; let $MYSQLD_DATADIR= `select @@datadir`; ---exec $MYSQL_BINLOG --force-if-open --start-position=134 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog +--exec $MYSQL_BINLOG --force-if-open --start-position=135 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog")) diff --git a/mysql-test/suite/binlog/t/binlog_killed_simulate.test b/mysql-test/suite/binlog/t/binlog_killed_simulate.test index ec61271ae88..f9240291dba 100644 --- a/mysql-test/suite/binlog/t/binlog_killed_simulate.test +++ b/mysql-test/suite/binlog/t/binlog_killed_simulate.test @@ -24,7 +24,7 @@ update t1 set a=2 /* will be "killed" after work has been done */; # for some constants like the offset of the first real event # that is different between severs versions. let $MYSQLD_DATADIR= `select @@datadir`; ---exec $MYSQL_BINLOG --force-if-open --start-position=106 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --force-if-open --start-position=107 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) @@ -52,7 +52,7 @@ load data infile '../../std_data/rpl_loaddata.dat' into table t2 /* will be "kil source include/show_binlog_events.inc; ---exec $MYSQL_BINLOG --force-if-open --start-position=98 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog +--exec $MYSQL_BINLOG --force-if-open --start-position=107 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval select (@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) diff --git a/mysql-test/suite/rpl/r/rpl_binlog_grant.result b/mysql-test/suite/rpl/r/rpl_binlog_grant.result index 4a789f361c6..2a7e4401500 100644 --- a/mysql-test/suite/rpl/r/rpl_binlog_grant.result +++ b/mysql-test/suite/rpl/r/rpl_binlog_grant.result @@ -17,16 +17,15 @@ show grants for x@y; Grants for x@y GRANT USAGE ON *.* TO 'x'@'y' GRANT SELECT ON `d1`.`t` TO 'x'@'y' -show binlog events; +show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 106 Query 1 193 drop database if exists d1 -master-bin.000001 193 Query 1 272 create database d1 -master-bin.000001 272 Query 1 370 use `d1`; create table t (s1 int) engine=innodb -master-bin.000001 370 Query 1 436 BEGIN -master-bin.000001 436 Query 1 521 use `d1`; insert into t values (1) -master-bin.000001 521 Xid 1 548 COMMIT /* XID */ -master-bin.000001 548 Query 1 633 use `d1`; grant select on t to x@y +master-bin.000001 # Query # # drop database if exists d1 +master-bin.000001 # Query # # create database d1 +master-bin.000001 # Query # # use `d1`; create table t (s1 int) engine=innodb +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `d1`; insert into t values (1) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `d1`; grant select on t to x@y start transaction; insert into t values (2); revoke select on t from x@y; @@ -38,19 +37,18 @@ s1 show grants for x@y; Grants for x@y GRANT USAGE ON *.* TO 'x'@'y' -show binlog events; +show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 106 Query 1 193 drop database if exists d1 -master-bin.000001 193 Query 1 272 create database d1 -master-bin.000001 272 Query 1 370 use `d1`; create table t (s1 int) engine=innodb -master-bin.000001 370 Query 1 436 BEGIN -master-bin.000001 436 Query 1 521 use `d1`; insert into t values (1) -master-bin.000001 521 Xid 1 548 COMMIT /* XID */ -master-bin.000001 548 Query 1 633 use `d1`; grant select on t to x@y -master-bin.000001 633 Query 1 699 BEGIN -master-bin.000001 699 Query 1 784 use `d1`; insert into t values (2) -master-bin.000001 784 Xid 1 811 COMMIT /* XID */ -master-bin.000001 811 Query 1 899 use `d1`; revoke select on t from x@y +master-bin.000001 # Query # # drop database if exists d1 +master-bin.000001 # Query # # create database d1 +master-bin.000001 # Query # # use `d1`; create table t (s1 int) engine=innodb +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `d1`; insert into t values (1) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `d1`; grant select on t to x@y +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `d1`; insert into t values (2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `d1`; revoke select on t from x@y drop user x@y; drop database d1; diff --git a/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result b/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result index 6c8d35619e5..9b54498d809 100644 --- a/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result @@ -157,7 +157,7 @@ SET @my_max_relay_log_size= @@global.max_relay_log_size; SET global max_relay_log_size=0; include/stop_slave.inc DELETE FROM t2; -CHANGE MASTER TO MASTER_LOG_POS=440; +CHANGE MASTER TO MASTER_LOG_POS=441; BEGIN; SELECT * FROM t1 FOR UPDATE; a diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result index e2ec78e7adc..fd208055bea 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result @@ -435,7 +435,7 @@ Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno 1364 -Last_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 330 +Last_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 331 Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -453,7 +453,7 @@ Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1364 -Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 330 +Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 331 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Create t10 on slave *** diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result index ed5b4eac27d..e50caa8861e 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result @@ -435,7 +435,7 @@ Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno 1364 -Last_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 330 +Last_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 331 Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -453,7 +453,7 @@ Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1364 -Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 330 +Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 331 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Create t10 on slave *** diff --git a/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result b/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result index 75180334c28..3055216cbd9 100644 --- a/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result +++ b/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result @@ -33,7 +33,7 @@ Replicate_Wild_Ignore_Table Last_Errno 1105 Last_Error Error 'master may suffer from http://bugs.mysql.com/bug.php?id=24432 so slave stops; check error log on slave for more info' on query. Default database: 'test'. Query: 'INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10' Skip_Counter 0 -Exec_Master_Log_Pos 246 +Exec_Master_Log_Pos 247 Relay_Log_Space # Until_Condition None Until_Log_File @@ -120,7 +120,7 @@ FROM t2 ON DUPLICATE KEY UPDATE t1.field_3 = t2.field_c' Skip_Counter 0 -Exec_Master_Log_Pos 1278 +Exec_Master_Log_Pos 1279 Relay_Log_Space # Until_Condition None Until_Log_File diff --git a/mysql-test/suite/rpl/r/rpl_loaddata.result b/mysql-test/suite/rpl/r/rpl_loaddata.result index d7a02bc84a5..141bbaeb95e 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata.result @@ -34,9 +34,45 @@ insert into t1 values(1,10); load data infile '../../std_data/rpl_loaddata.dat' into table t1; set global sql_slave_skip_counter=1; start slave; -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1797 # # master-bin.000001 Yes Yes # 0 0 1797 # None 0 No # No 0 0 +show slave status;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 1798 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table # +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 1798 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error set sql_log_bin=0; delete from t1; set sql_log_bin=1; @@ -44,9 +80,45 @@ load data infile '../../std_data/rpl_loaddata.dat' into table t1; stop slave; change master to master_user='test'; change master to master_user='root'; -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1832 # # master-bin.000001 No No # 0 0 1832 # None 0 No # No 0 0 +show slave status;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 1833 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running No +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table # +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 1833 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error set global sql_slave_skip_counter=1; start slave; set sql_log_bin=0; @@ -55,9 +127,45 @@ set sql_log_bin=1; load data infile '../../std_data/rpl_loaddata.dat' into table t1; stop slave; reset slave; -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error -# 127.0.0.1 root MASTER_PORT 1 4 # # No No # 0 0 0 # None 0 No # No 0 0 +show slave status;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File +Read_Master_Log_Pos 4 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File +Slave_IO_Running No +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table # +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 0 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error reset master; create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), unique(day)) engine=MyISAM; diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result index 27fb8623e85..cb2accc86ca 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result @@ -13,7 +13,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 290 +Read_Master_Log_Pos 291 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -28,7 +28,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 290 +Exec_Master_Log_Pos 291 Relay_Log_Space # Until_Condition None Until_Log_File @@ -53,7 +53,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 465 +Read_Master_Log_Pos 466 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -68,7 +68,7 @@ Replicate_Wild_Ignore_Table Last_Errno 1593 Last_Error Fatal error: Not enough memory Skip_Counter 0 -Exec_Master_Log_Pos 325 +Exec_Master_Log_Pos 326 Relay_Log_Space # Until_Condition None Until_Log_File diff --git a/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result b/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result index 2e707fb62c1..59726ea5661 100644 --- a/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result +++ b/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result @@ -31,7 +31,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 594 +Read_Master_Log_Pos 595 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -46,7 +46,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 594 +Exec_Master_Log_Pos 595 Relay_Log_Space # Until_Condition None Until_Log_File diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result index 7920b9a981d..27960be8054 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result @@ -58,12 +58,12 @@ DELETE FROM t1 WHERE a = 0; UPDATE t1 SET a=99 WHERE a = 0; SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server ver: SERVER_VERSION, Binlog ver: 4 -master-bin.000001 106 Query 1 192 use `test`; CREATE TABLE t1 (a INT) -master-bin.000001 192 Query 1 260 BEGIN -master-bin.000001 260 Table_map 1 301 table_id: # (test.t1) -master-bin.000001 301 Write_rows 1 340 table_id: # flags: STMT_END_F -master-bin.000001 340 Query 1 409 COMMIT +master-bin.000001 4 Format_desc 1 107 Server ver: SERVER_VERSION, Binlog ver: 4 +master-bin.000001 107 Query 1 193 use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 193 Query 1 261 BEGIN +master-bin.000001 261 Table_map 1 302 table_id: # (test.t1) +master-bin.000001 302 Write_rows 1 341 table_id: # flags: STMT_END_F +master-bin.000001 341 Query 1 410 COMMIT DROP TABLE t1; ================ Test for BUG#17620 ================ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; diff --git a/mysql-test/suite/rpl/r/rpl_row_conflicts.result b/mysql-test/suite/rpl/r/rpl_row_conflicts.result index 0f15bfc7156..6f98c25c335 100644 --- a/mysql-test/suite/rpl/r/rpl_row_conflicts.result +++ b/mysql-test/suite/rpl/r/rpl_row_conflicts.result @@ -24,7 +24,7 @@ a 1 [on slave] ---- Wait until slave stops with an error ---- -Last_SQL_Error = Could not execute Write_rows event on table test.t1; Duplicate entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log master-bin.000001, end_log_pos 346 (expected "duplicate key" error) +Last_SQL_Error = Could not execute Write_rows event on table test.t1; Duplicate entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log master-bin.000001, end_log_pos 347 (expected "duplicate key" error) SELECT * FROM t1; a 1 @@ -50,7 +50,7 @@ SELECT * FROM t1; a [on slave] ---- Wait until slave stops with an error ---- -Last_SQL_Error = Could not execute Delete_rows event on table test.t1; Can't find record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log master-bin.000001, end_log_pos 982 (expected "can't find record" error) +Last_SQL_Error = Could not execute Delete_rows event on table test.t1; Can't find record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log master-bin.000001, end_log_pos 983 (expected "can't find record" error) SELECT * FROM t1; a ---- Resolve the conflict on the slave and restart SQL thread ---- diff --git a/mysql-test/suite/rpl/r/rpl_row_create_table.result b/mysql-test/suite/rpl/r/rpl_row_create_table.result index 5bed9106009..acee168baf2 100644 --- a/mysql-test/suite/rpl/r/rpl_row_create_table.result +++ b/mysql-test/suite/rpl/r/rpl_row_create_table.result @@ -13,30 +13,30 @@ CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT, b INT) ENGINE=Merge; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8; -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; Log_name # -Pos 106 +Pos 107 Event_type Query Server_id # -End_log_pos 199 +End_log_pos 200 Info use `test`; CREATE TABLE t1 (a INT, b INT) Log_name # -Pos 199 +Pos 200 Event_type Query Server_id # -End_log_pos 305 +End_log_pos 306 Info use `test`; CREATE TABLE t2 (a INT, b INT) ENGINE=Merge Log_name # -Pos 305 +Pos 306 Event_type Query Server_id # -End_log_pos 411 +End_log_pos 412 Info use `test`; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8 Log_name # -Pos 411 +Pos 412 Event_type Query Server_id # -End_log_pos 530 +End_log_pos 531 Info use `test`; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8 **** On Master **** SHOW CREATE TABLE t1; @@ -137,7 +137,7 @@ RESET MASTER; include/start_slave.inc CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3; ERROR 23000: Duplicate entry '2' for key 'b' -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; Log_name Pos Event_type Server_id End_log_pos Info CREATE TABLE t7 (a INT, b INT UNIQUE); INSERT INTO t7 SELECT a,b FROM tt3; @@ -147,13 +147,13 @@ a b 1 2 2 4 3 6 -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; Log_name Pos Event_type Server_id End_log_pos Info -# 106 Query # 206 use `test`; CREATE TABLE t7 (a INT, b INT UNIQUE) -# 206 Query # 274 BEGIN -# 274 Table_map # 316 table_id: # (test.t7) -# 316 Write_rows # 372 table_id: # flags: STMT_END_F -# 372 Query # 443 ROLLBACK +# 107 Query # 207 use `test`; CREATE TABLE t7 (a INT, b INT UNIQUE) +# 207 Query # 275 BEGIN +# 275 Table_map # 317 table_id: # (test.t7) +# 317 Write_rows # 373 table_id: # flags: STMT_END_F +# 373 Query # 444 ROLLBACK SELECT * FROM t7 ORDER BY a,b; a b 1 2 @@ -171,12 +171,12 @@ INSERT INTO t7 SELECT a,b FROM tt4; ROLLBACK; Warnings: Warning 1196 Some non-transactional changed tables couldn't be rolled back -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; Log_name Pos Event_type Server_id End_log_pos Info -# 106 Query # 174 BEGIN -# 174 Table_map # 216 table_id: # (test.t7) -# 216 Write_rows # 272 table_id: # flags: STMT_END_F -# 272 Query # 343 ROLLBACK +# 107 Query # 175 BEGIN +# 175 Table_map # 217 table_id: # (test.t7) +# 217 Write_rows # 273 table_id: # flags: STMT_END_F +# 273 Query # 344 ROLLBACK SELECT * FROM t7 ORDER BY a,b; a b 1 2 @@ -216,10 +216,10 @@ Create Table CREATE TABLE `t9` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; Log_name Pos Event_type Server_id End_log_pos Info -# 106 Query # 192 use `test`; CREATE TABLE t8 LIKE t4 -# 192 Query # 331 use `test`; CREATE TABLE `t9` ( +# 107 Query # 193 use `test`; CREATE TABLE t8 LIKE t4 +# 193 Query # 332 use `test`; CREATE TABLE `t9` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL ) @@ -296,38 +296,38 @@ a 1 2 3 -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; Log_name Pos Event_type Server_id End_log_pos Info -# 106 Query # 192 use `test`; CREATE TABLE t1 (a INT) -# 192 Query # 260 BEGIN -# 260 Table_map # 301 table_id: # (test.t1) -# 301 Write_rows # 345 table_id: # flags: STMT_END_F -# 345 Query # 414 COMMIT -# 414 Query # 482 BEGIN -# 482 Query # 607 use `test`; CREATE TABLE `t2` ( +# 107 Query # 193 use `test`; CREATE TABLE t1 (a INT) +# 193 Query # 261 BEGIN +# 261 Table_map # 302 table_id: # (test.t1) +# 302 Write_rows # 346 table_id: # flags: STMT_END_F +# 346 Query # 415 COMMIT +# 415 Query # 483 BEGIN +# 483 Query # 608 use `test`; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB -# 607 Table_map # 648 table_id: # (test.t2) -# 648 Write_rows # 692 table_id: # flags: STMT_END_F -# 692 Xid # 719 COMMIT /* XID */ -# 719 Query # 787 BEGIN -# 787 Query # 912 use `test`; CREATE TABLE `t3` ( +# 608 Table_map # 649 table_id: # (test.t2) +# 649 Write_rows # 693 table_id: # flags: STMT_END_F +# 693 Xid # 720 COMMIT /* XID */ +# 720 Query # 788 BEGIN +# 788 Query # 913 use `test`; CREATE TABLE `t3` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB -# 912 Table_map # 953 table_id: # (test.t3) -# 953 Write_rows # 997 table_id: # flags: STMT_END_F -# 997 Xid # 1024 COMMIT /* XID */ -# 1024 Query # 1092 BEGIN -# 1092 Query # 1217 use `test`; CREATE TABLE `t4` ( +# 913 Table_map # 954 table_id: # (test.t3) +# 954 Write_rows # 998 table_id: # flags: STMT_END_F +# 998 Xid # 1025 COMMIT /* XID */ +# 1025 Query # 1093 BEGIN +# 1093 Query # 1218 use `test`; CREATE TABLE `t4` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB -# 1217 Table_map # 1258 table_id: # (test.t4) -# 1258 Write_rows # 1302 table_id: # flags: STMT_END_F -# 1302 Xid # 1329 COMMIT /* XID */ -# 1329 Query # 1397 BEGIN -# 1397 Table_map # 1438 table_id: # (test.t1) -# 1438 Write_rows # 1482 table_id: # flags: STMT_END_F -# 1482 Query # 1553 ROLLBACK +# 1218 Table_map # 1259 table_id: # (test.t4) +# 1259 Write_rows # 1303 table_id: # flags: STMT_END_F +# 1303 Xid # 1330 COMMIT /* XID */ +# 1330 Query # 1398 BEGIN +# 1398 Table_map # 1439 table_id: # (test.t1) +# 1439 Write_rows # 1483 table_id: # flags: STMT_END_F +# 1483 Query # 1554 ROLLBACK SHOW TABLES; Tables_in_test t1 @@ -390,20 +390,20 @@ a 4 6 9 -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; Log_name Pos Event_type Server_id End_log_pos Info -# 106 Query # 192 use `test`; CREATE TABLE t1 (a INT) -# 192 Query # 260 BEGIN -# 260 Table_map # 301 table_id: # (test.t1) -# 301 Write_rows # 345 table_id: # flags: STMT_END_F -# 345 Query # 414 COMMIT -# 414 Query # 514 use `test`; CREATE TABLE t2 (a INT) ENGINE=INNODB -# 514 Query # 582 BEGIN -# 582 Table_map # 623 table_id: # (test.t2) -# 623 Write_rows # 667 table_id: # flags: STMT_END_F -# 667 Table_map # 708 table_id: # (test.t2) -# 708 Write_rows # 747 table_id: # flags: STMT_END_F -# 747 Xid # 774 COMMIT /* XID */ +# 107 Query # 193 use `test`; CREATE TABLE t1 (a INT) +# 193 Query # 261 BEGIN +# 261 Table_map # 302 table_id: # (test.t1) +# 302 Write_rows # 346 table_id: # flags: STMT_END_F +# 346 Query # 415 COMMIT +# 415 Query # 515 use `test`; CREATE TABLE t2 (a INT) ENGINE=INNODB +# 515 Query # 583 BEGIN +# 583 Table_map # 624 table_id: # (test.t2) +# 624 Write_rows # 668 table_id: # flags: STMT_END_F +# 668 Table_map # 709 table_id: # (test.t2) +# 709 Write_rows # 748 table_id: # flags: STMT_END_F +# 748 Xid # 775 COMMIT /* XID */ SELECT * FROM t2 ORDER BY a; a 1 @@ -429,14 +429,14 @@ Warnings: Warning 1196 Some non-transactional changed tables couldn't be rolled back SELECT * FROM t2 ORDER BY a; a -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; Log_name Pos Event_type Server_id End_log_pos Info -# 106 Query # 174 BEGIN -# 174 Table_map # 215 table_id: # (test.t2) -# 215 Write_rows # 259 table_id: # flags: STMT_END_F -# 259 Table_map # 300 table_id: # (test.t2) -# 300 Write_rows # 339 table_id: # flags: STMT_END_F -# 339 Query # 410 ROLLBACK +# 107 Query # 175 BEGIN +# 175 Table_map # 216 table_id: # (test.t2) +# 216 Write_rows # 260 table_id: # flags: STMT_END_F +# 260 Table_map # 301 table_id: # (test.t2) +# 301 Write_rows # 340 table_id: # flags: STMT_END_F +# 340 Query # 411 ROLLBACK SELECT * FROM t2 ORDER BY a; a DROP TABLE t1,t2; diff --git a/mysql-test/suite/rpl/r/rpl_row_drop.result b/mysql-test/suite/rpl/r/rpl_row_drop.result index 89654ebf165..f1a350b3df0 100644 --- a/mysql-test/suite/rpl/r/rpl_row_drop.result +++ b/mysql-test/suite/rpl/r/rpl_row_drop.result @@ -43,10 +43,10 @@ t2 DROP TABLE t1,t2; SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server ver: VERSION, Binlog ver: 4 -master-bin.000001 106 Query 1 192 use `test`; CREATE TABLE t1 (a int) -master-bin.000001 192 Query 1 278 use `test`; CREATE TABLE t2 (a int) -master-bin.000001 278 Query 1 382 use `test`; DROP TABLE `t1` /* generated by server */ +master-bin.000001 4 Format_desc 1 107 Server ver: VERSION, Binlog ver: 4 +master-bin.000001 107 Query 1 193 use `test`; CREATE TABLE t1 (a int) +master-bin.000001 193 Query 1 279 use `test`; CREATE TABLE t2 (a int) +master-bin.000001 279 Query 1 383 use `test`; DROP TABLE `t1` /* generated by server */ SHOW TABLES; Tables_in_test t2 diff --git a/mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result b/mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result index 129bad0fbcc..384573c0461 100644 --- a/mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result +++ b/mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result @@ -12,13 +12,13 @@ create table t4 (a int); insert into t4 select * from t3; rename table t1 to t5, t2 to t1; flush no_write_to_binlog tables; -SHOW BINLOG EVENTS FROM 897 ; +SHOW BINLOG EVENTS FROM 898 ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1 select * from t3; a flush tables; -SHOW BINLOG EVENTS FROM 897 ; +SHOW BINLOG EVENTS FROM 898 ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1 master-bin.000001 # Query 1 # use `test`; flush tables diff --git a/mysql-test/suite/rpl/r/rpl_row_log.result b/mysql-test/suite/rpl/r/rpl_row_log.result index 9593b009d1f..ca8fba3b6bd 100644 --- a/mysql-test/suite/rpl/r/rpl_row_log.result +++ b/mysql-test/suite/rpl/r/rpl_row_log.result @@ -30,14 +30,14 @@ master-bin.000001 # Query 1 # BEGIN master-bin.000001 # Table_map 1 # table_id: # (test.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Query 1 # COMMIT -show binlog events from 106 limit 1; +show binlog events from 107 limit 1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM -show binlog events from 106 limit 2; +show binlog events from 107 limit 2; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM master-bin.000001 # Query 1 # BEGIN -show binlog events from 106 limit 2,1; +show binlog events from 107 limit 2,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Table_map 1 # table_id: # (test.t1) flush logs; @@ -251,7 +251,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000002 -Read_Master_Log_Pos 516 +Read_Master_Log_Pos 517 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000002 @@ -266,7 +266,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 516 +Exec_Master_Log_Pos 517 Relay_Log_Space # Until_Condition None Until_Log_File diff --git a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result index 8526bad558b..9347f87ef8f 100644 --- a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result @@ -30,14 +30,14 @@ master-bin.000001 # Query 1 # BEGIN master-bin.000001 # Table_map 1 # table_id: # (test.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Xid 1 # COMMIT /* XID */ -show binlog events from 106 limit 1; +show binlog events from 107 limit 1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=InnoDB -show binlog events from 106 limit 2; +show binlog events from 107 limit 2; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=InnoDB master-bin.000001 # Query 1 # BEGIN -show binlog events from 106 limit 2,1; +show binlog events from 107 limit 2,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Table_map 1 # table_id: # (test.t1) flush logs; @@ -251,7 +251,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000002 -Read_Master_Log_Pos 474 +Read_Master_Log_Pos 475 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000002 @@ -266,7 +266,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 474 +Exec_Master_Log_Pos 475 Relay_Log_Space # Until_Condition None Until_Log_File diff --git a/mysql-test/suite/rpl/r/rpl_slave_skip.result b/mysql-test/suite/rpl/r/rpl_slave_skip.result index 6148de5d954..41076f9fee3 100644 --- a/mysql-test/suite/rpl/r/rpl_slave_skip.result +++ b/mysql-test/suite/rpl/r/rpl_slave_skip.result @@ -50,7 +50,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 1115 +Read_Master_Log_Pos 1116 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -65,7 +65,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 762 +Exec_Master_Log_Pos 763 Relay_Log_Space # Until_Condition Master Until_Log_File master-bin.000001 @@ -114,7 +114,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 248 +Read_Master_Log_Pos 249 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -129,7 +129,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 248 +Exec_Master_Log_Pos 249 Relay_Log_Space # Until_Condition None Until_Log_File diff --git a/mysql-test/suite/rpl/r/rpl_sp.result b/mysql-test/suite/rpl/r/rpl_sp.result index 90a362c352b..e2946bb487a 100644 --- a/mysql-test/suite/rpl/r/rpl_sp.result +++ b/mysql-test/suite/rpl/r/rpl_sp.result @@ -409,110 +409,110 @@ return 0; end| use mysqltest; set @a:= mysqltest2.f1(); -show binlog events in 'master-bin.000001' from 106; +show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # drop database if exists mysqltest1 -master-bin.000001 # Query 1 # create database mysqltest1 -master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a varchar(100)) -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +master-bin.000001 # Query # # drop database if exists mysqltest1 +master-bin.000001 # Query # # create database mysqltest1 +master-bin.000001 # Query # # use `mysqltest1`; create table t1 (a varchar(100)) +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() begin declare b int; set b = 8; insert into t1 values (b); insert into t1 values (unix_timestamp()); end -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8)) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp()) -master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo2`() +master-bin.000001 # Query # # use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8)) +master-bin.000001 # Query # # use `mysqltest1`; insert into t1 values (unix_timestamp()) +master-bin.000001 # Query # # use `mysqltest1`; delete from t1 +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo2`() select * from mysqltest1.t1 -master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo2 contains sql -master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1 -master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int) -master-bin.000001 # Query 1 # use `mysqltest1`; create table t2 like t1 -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo3`() +master-bin.000001 # Query # # use `mysqltest1`; alter procedure foo2 contains sql +master-bin.000001 # Query # # use `mysqltest1`; drop table t1 +master-bin.000001 # Query # # use `mysqltest1`; create table t1 (a int) +master-bin.000001 # Query # # use `mysqltest1`; create table t2 like t1 +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo3`() DETERMINISTIC insert into t1 values (15) -master-bin.000001 # Query 1 # use `mysqltest1`; grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1 -master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1 -master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1 -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` PROCEDURE `foo4`() +master-bin.000001 # Query # # use `mysqltest1`; grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query # # use `mysqltest1`; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query # # use `mysqltest1`; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` PROCEDURE `foo4`() DETERMINISTIC begin insert into t2 values(3); insert into t1 values (5); end -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (15) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) -master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo4 sql security invoker -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (5) -master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 -master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) -master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo4`() +master-bin.000001 # Query # # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query # # use `mysqltest1`; insert into t1 values (15) +master-bin.000001 # Query # # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query # # use `mysqltest1`; alter procedure foo4 sql security invoker +master-bin.000001 # Query # # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query # # use `mysqltest1`; insert into t1 values (5) +master-bin.000001 # Query # # use `mysqltest1`; delete from t2 +master-bin.000001 # Query # # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query # # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo4`() DETERMINISTIC begin insert into t2 values(20),(20); end -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(20),(20) -master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 -master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo -master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo2 -master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo3 -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION `fn1`(x int) RETURNS int(11) +master-bin.000001 # Query # # use `mysqltest1`; insert into t2 values(20),(20) +master-bin.000001 # Query # # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query # # use `mysqltest1`; drop procedure foo +master-bin.000001 # Query # # use `mysqltest1`; drop procedure foo2 +master-bin.000001 # Query # # use `mysqltest1`; drop procedure foo3 +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION `fn1`(x int) RETURNS int(11) DETERMINISTIC begin insert into t1 values (x); return x+2; end -master-bin.000001 # Query 1 # use `mysqltest1`; delete t1,t2 from t1,t2 -master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `mysqltest1`.`fn1`(20) -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(fn1(21)) -master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION `fn1`() RETURNS int(11) +master-bin.000001 # Query # # use `mysqltest1`; delete t1,t2 from t1,t2 +master-bin.000001 # Query # # use `mysqltest1`; SELECT `mysqltest1`.`fn1`(20) +master-bin.000001 # Query # # use `mysqltest1`; insert into t2 values(fn1(21)) +master-bin.000001 # Query # # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION `fn1`() RETURNS int(11) NO SQL begin return unix_timestamp(); end -master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(fn1()) -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` FUNCTION `fn2`() RETURNS int(11) +master-bin.000001 # Query # # use `mysqltest1`; delete from t1 +master-bin.000001 # Query # # use `mysqltest1`; insert into t1 values(fn1()) +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` FUNCTION `fn2`() RETURNS int(11) NO SQL begin return unix_timestamp(); end -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION `fn3`() RETURNS int(11) +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION `fn3`() RETURNS int(11) READS SQL DATA begin return 0; end -master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 -master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) -master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION `fn1`(x int) RETURNS int(11) +master-bin.000001 # Query # # use `mysqltest1`; delete from t2 +master-bin.000001 # Query # # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query # # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION `fn1`(x int) RETURNS int(11) begin insert into t2 values(x),(x); return 10; end -master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `mysqltest1`.`fn1`(100) -master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `mysqltest1`.`fn1`(20) -master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10 -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) -master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 -master-bin.000001 # Query 1 # use `mysqltest1`; drop trigger trg -master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) -master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() +master-bin.000001 # Query # # use `mysqltest1`; SELECT `mysqltest1`.`fn1`(100) +master-bin.000001 # Query # # use `mysqltest1`; SELECT `mysqltest1`.`fn1`(20) +master-bin.000001 # Query # # use `mysqltest1`; delete from t1 +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10 +master-bin.000001 # Query # # use `mysqltest1`; insert into t1 values (1) +master-bin.000001 # Query # # use `mysqltest1`; delete from t1 +master-bin.000001 # Query # # use `mysqltest1`; drop trigger trg +master-bin.000001 # Query # # use `mysqltest1`; insert into t1 values (1) +master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`() READS SQL DATA select * from t1 -master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo -master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 -master-bin.000001 # Query 1 # drop database mysqltest1 -master-bin.000001 # Query 1 # drop user "zedjzlcsjhd"@127.0.0.1 -master-bin.000001 # Query 1 # use `test`; drop function if exists f1 -master-bin.000001 # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) +master-bin.000001 # Query # # use `mysqltest1`; drop procedure foo +master-bin.000001 # Query # # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query # # drop database mysqltest1 +master-bin.000001 # Query # # drop user "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query # # use `test`; drop function if exists f1 +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) READS SQL DATA begin declare var integer; @@ -522,41 +522,41 @@ fetch c into var; close c; return var; end -master-bin.000001 # Query 1 # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 as a -master-bin.000001 # Query 1 # use `test`; create table t1 (a int) -master-bin.000001 # Query 1 # use `test`; insert into t1 (a) values (f1()) -master-bin.000001 # Query 1 # use `test`; drop view v1 -master-bin.000001 # Query 1 # use `test`; drop function f1 -master-bin.000001 # Query 1 # use `test`; DROP PROCEDURE IF EXISTS p1 -master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS t1 -master-bin.000001 # Query 1 # use `test`; CREATE TABLE t1(col VARCHAR(10)) -master-bin.000001 # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`(arg VARCHAR(10)) +master-bin.000001 # Query # # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 as a +master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Query # # use `test`; insert into t1 (a) values (f1()) +master-bin.000001 # Query # # use `test`; drop view v1 +master-bin.000001 # Query # # use `test`; drop function f1 +master-bin.000001 # Query # # use `test`; DROP PROCEDURE IF EXISTS p1 +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1 +master-bin.000001 # Query # # use `test`; CREATE TABLE t1(col VARCHAR(10)) +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`(arg VARCHAR(10)) INSERT INTO t1 VALUES(arg) -master-bin.000001 # Query 1 # use `test`; INSERT INTO t1 VALUES( NAME_CONST('arg',_latin1'test' COLLATE 'latin1_swedish_ci')) -master-bin.000001 # Query 1 # use `test`; DROP PROCEDURE p1 -master-bin.000001 # Query 1 # use `test`; DROP PROCEDURE IF EXISTS p1 -master-bin.000001 # Query 1 # use `test`; DROP FUNCTION IF EXISTS f1 -master-bin.000001 # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES( NAME_CONST('arg',_latin1'test' COLLATE 'latin1_swedish_ci')) +master-bin.000001 # Query # # use `test`; DROP PROCEDURE p1 +master-bin.000001 # Query # # use `test`; DROP PROCEDURE IF EXISTS p1 +master-bin.000001 # Query # # use `test`; DROP FUNCTION IF EXISTS f1 +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() SET @a = 1 -master-bin.000001 # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) RETURN 0 -master-bin.000001 # Query 1 # use `test`; DROP PROCEDURE p1 -master-bin.000001 # Query 1 # use `test`; DROP FUNCTION f1 -master-bin.000001 # Query 1 # use `test`; drop table t1 -master-bin.000001 # Query 1 # drop database if exists mysqltest -master-bin.000001 # Query 1 # drop database if exists mysqltest2 -master-bin.000001 # Query 1 # create database mysqltest -master-bin.000001 # Query 1 # create database mysqltest2 -master-bin.000001 # Query 1 # use `mysqltest2`; create table t ( t integer ) -master-bin.000001 # Query 1 # use `mysqltest2`; CREATE DEFINER=`root`@`localhost` PROCEDURE `mysqltest`.`test`() +master-bin.000001 # Query # # use `test`; DROP PROCEDURE p1 +master-bin.000001 # Query # # use `test`; DROP FUNCTION f1 +master-bin.000001 # Query # # use `test`; drop table t1 +master-bin.000001 # Query # # drop database if exists mysqltest +master-bin.000001 # Query # # drop database if exists mysqltest2 +master-bin.000001 # Query # # create database mysqltest +master-bin.000001 # Query # # create database mysqltest2 +master-bin.000001 # Query # # use `mysqltest2`; create table t ( t integer ) +master-bin.000001 # Query # # use `mysqltest2`; CREATE DEFINER=`root`@`localhost` PROCEDURE `mysqltest`.`test`() begin end -master-bin.000001 # Query 1 # use `mysqltest2`; insert into t values ( 1 ) -master-bin.000001 # Query 1 # use `mysqltest2`; CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) +master-bin.000001 # Query # # use `mysqltest2`; insert into t values ( 1 ) +master-bin.000001 # Query # # use `mysqltest2`; CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) begin insert into t values (1); return 0; end -master-bin.000001 # Query 1 # use `mysqltest`; SELECT `mysqltest2`.`f1`() +master-bin.000001 # Query # # use `mysqltest`; SELECT `mysqltest2`.`f1`() set @@global.log_bin_trust_routine_creators= @old_log_bin_trust_routine_creators; Warnings: Warning 1287 The syntax '@@log_bin_trust_routine_creators' is deprecated and will be removed in MySQL 6.0. Please use '@@log_bin_trust_function_creators' instead diff --git a/mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result b/mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result index 74031af1dde..1f6c86768b5 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result +++ b/mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result @@ -12,13 +12,13 @@ create table t4 (a int); insert into t4 select * from t3; rename table t1 to t5, t2 to t1; flush no_write_to_binlog tables; -SHOW BINLOG EVENTS FROM 656 ; +SHOW BINLOG EVENTS FROM 657 ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1 select * from t3; a flush tables; -SHOW BINLOG EVENTS FROM 656 ; +SHOW BINLOG EVENTS FROM 657 ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1 master-bin.000001 # Query 1 # use `test`; flush tables diff --git a/mysql-test/suite/rpl/r/rpl_stm_log.result b/mysql-test/suite/rpl/r/rpl_stm_log.result index bcefc6f9d3d..61eba2b4b3f 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_log.result +++ b/mysql-test/suite/rpl/r/rpl_stm_log.result @@ -26,14 +26,14 @@ master-bin.000001 # Query 1 # use `test`; drop table t1 master-bin.000001 # Query 1 # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM master-bin.000001 # Begin_load_query 1 # ;file_id=1;block_len=581 master-bin.000001 # Execute_load_query 1 # use `test`; load data infile '../../std_data/words.dat' into table t1 ignore 1 lines ;file_id=1 -show binlog events from 106 limit 1; +show binlog events from 107 limit 1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM -show binlog events from 106 limit 2; +show binlog events from 107 limit 2; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM master-bin.000001 # Intvar 1 # INSERT_ID=1 -show binlog events from 106 limit 2,1; +show binlog events from 107 limit 2,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; insert into t1 values (NULL) flush logs; @@ -233,7 +233,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000002 -Read_Master_Log_Pos 392 +Read_Master_Log_Pos 393 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000002 @@ -248,7 +248,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 392 +Exec_Master_Log_Pos 393 Relay_Log_Space # Until_Condition None Until_Log_File diff --git a/mysql-test/suite/rpl/t/rpl_binlog_grant.test b/mysql-test/suite/rpl/t/rpl_binlog_grant.test index 31163927ce2..da14b45d5c3 100644 --- a/mysql-test/suite/rpl/t/rpl_binlog_grant.test +++ b/mysql-test/suite/rpl/t/rpl_binlog_grant.test @@ -25,9 +25,7 @@ grant select on t to x@y; # rollback; show grants for x@y; ---replace_result $VERSION VERSION ---replace_regex /\/\* xid=.* \*\//\/* XID *\// -show binlog events; +source include/show_binlog_events.inc; start transaction; insert into t values (2); revoke select on t from x@y; @@ -37,9 +35,7 @@ revoke select on t from x@y; commit; select * from t; show grants for x@y; ---replace_result $VERSION VERSION ---replace_regex /\/\* xid=.* \*\//\/* XID *\// -show binlog events; +source include/show_binlog_events.inc; drop user x@y; drop database d1; --sync_slave_with_master diff --git a/mysql-test/suite/rpl/t/rpl_row_create_table.test b/mysql-test/suite/rpl/t/rpl_row_create_table.test index 319f9546a81..0d91d855a57 100644 --- a/mysql-test/suite/rpl/t/rpl_row_create_table.test +++ b/mysql-test/suite/rpl/t/rpl_row_create_table.test @@ -38,7 +38,7 @@ CREATE TABLE t3 (a INT, b INT) CHARSET=utf8; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8; --replace_column 1 # 4 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ ---query_vertical SHOW BINLOG EVENTS FROM 106 +--query_vertical SHOW BINLOG EVENTS FROM 107 --echo **** On Master **** --query_vertical SHOW CREATE TABLE t1 --query_vertical SHOW CREATE TABLE t2 @@ -76,7 +76,7 @@ CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3; # Shouldn't be written to the binary log --replace_column 1 # 4 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; # Test that INSERT-SELECT works the same way as for SBR. CREATE TABLE t7 (a INT, b INT UNIQUE); @@ -86,7 +86,7 @@ SELECT * FROM t7 ORDER BY a,b; # Should be written to the binary log --replace_column 1 # 4 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; sync_slave_with_master; SELECT * FROM t7 ORDER BY a,b; @@ -100,7 +100,7 @@ INSERT INTO t7 SELECT a,b FROM tt4; ROLLBACK; --replace_column 1 # 4 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; SELECT * FROM t7 ORDER BY a,b; sync_slave_with_master; SELECT * FROM t7 ORDER BY a,b; @@ -118,7 +118,7 @@ CREATE TEMPORARY TABLE tt7 SELECT 1; --query_vertical SHOW CREATE TABLE t9 --replace_column 1 # 4 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; sync_slave_with_master; --echo **** On Slave **** --query_vertical SHOW CREATE TABLE t8 @@ -170,7 +170,7 @@ SELECT * FROM t3 ORDER BY a; SELECT * FROM t4 ORDER BY a; --replace_column 1 # 4 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; sync_slave_with_master; SHOW TABLES; SELECT TABLE_NAME,ENGINE @@ -216,7 +216,7 @@ COMMIT; SELECT * FROM t2 ORDER BY a; --replace_column 1 # 4 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; sync_slave_with_master; SELECT * FROM t2 ORDER BY a; @@ -239,7 +239,7 @@ ROLLBACK; SELECT * FROM t2 ORDER BY a; --replace_column 1 # 4 # --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ -SHOW BINLOG EVENTS FROM 106; +SHOW BINLOG EVENTS FROM 107; sync_slave_with_master; SELECT * FROM t2 ORDER BY a; diff --git a/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test b/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test index 667e1d9a1a8..d2996bbe525 100644 --- a/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test +++ b/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test @@ -1,7 +1,7 @@ # depends on the binlog output -- source include/have_binlog_format_row.inc -let $rename_event_pos= 897; +let $rename_event_pos= 898; # Bug#18326: Do not lock table for writing during prepare of statement # The use of the ps protocol causes extra table maps in the binlog, so diff --git a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test index 3328d582692..a7967f6643a 100644 --- a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test +++ b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test @@ -164,13 +164,13 @@ remove_file $MYSQLTEST_VARDIR/tmp/master.sql; # this test for position option -# By setting this position to 416, we should only get the create of t3 +# By setting this position to 417, we should only get the create of t3 --disable_query_log select "--- Test 2 position test --" as ""; --enable_query_log let $MYSQLD_DATADIR= `select @@datadir;`; --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR ---exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --position=416 --stop-position=569 $MYSQLD_DATADIR/master-bin.000001 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --position=417 --stop-position=570 $MYSQLD_DATADIR/master-bin.000001 # These are tests for remote binlog. # They should return the same as previous test. @@ -181,7 +181,7 @@ select "--- Test 3 First Remote test --" as ""; # This is broken now --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR ---exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --stop-position=569 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --stop-position=570 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 # This part is disabled due to bug #17654 @@ -272,7 +272,7 @@ let $MYSQLD_DATADIR= `select @@datadir;`; select "--- Test 7 reading stdin w/position --" as ""; --enable_query_log --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form --position=416 --stop-position=569 - < $MYSQLD_DATADIR/master-bin.000001 +--exec $MYSQL_BINLOG --short-form --position=417 --stop-position=569 - < $MYSQLD_DATADIR/master-bin.000001 # Bug#16217 (mysql client did not know how not switch its internal charset) --disable_query_log diff --git a/mysql-test/suite/rpl/t/rpl_sp.test b/mysql-test/suite/rpl/t/rpl_sp.test index 9be630e9ae8..2811db8ef1e 100644 --- a/mysql-test/suite/rpl/t/rpl_sp.test +++ b/mysql-test/suite/rpl/t/rpl_sp.test @@ -568,9 +568,7 @@ connection master; # Final inspection which verifies how all statements of this test file # were written to the binary log. ---replace_column 2 # 5 # ---replace_regex /table_id: [0-9]+/table_id: #/ -show binlog events in 'master-bin.000001' from 106; +source include/show_binlog_events.inc; # Restore log_bin_trust_function_creators to its original value. diff --git a/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test b/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test index a8a33d05e8b..f3993f80b90 100644 --- a/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test +++ b/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test @@ -1,7 +1,7 @@ # depends on the binlog output --source include/have_binlog_format_mixed_or_statement.inc -let $rename_event_pos= 656; +let $rename_event_pos= 657; -- source extra/rpl_tests/rpl_flsh_tbls.test # End of 4.1 tests diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result index 540c430e757..86752fbc4b8 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result @@ -34,14 +34,14 @@ master-bin.000001 # Table_map 1 # table_id: # (mysql.ndb_apply_status) master-bin.000001 # Write_rows 1 # table_id: # master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Query 1 # COMMIT -show binlog events from 106 limit 1; +show binlog events from 107 limit 1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=NDB -show binlog events from 106 limit 2; +show binlog events from 107 limit 2; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=NDB master-bin.000001 # Query 1 # BEGIN -show binlog events from 106 limit 2,1; +show binlog events from 107 limit 2,1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Table_map 1 # table_id: # (test.t1) flush logs; @@ -267,7 +267,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000002 -Read_Master_Log_Pos 623 +Read_Master_Log_Pos 624 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000002 @@ -282,7 +282,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 623 +Exec_Master_Log_Pos 624 Relay_Log_Space # Until_Condition None Until_Log_File diff --git a/mysql-test/suite/rpl_ndb/r/rpl_truncate_7ndb.result b/mysql-test/suite/rpl_ndb/r/rpl_truncate_7ndb.result index d6c57aed41b..6c9e20fd56a 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_truncate_7ndb.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_truncate_7ndb.result @@ -29,16 +29,16 @@ a b DROP TABLE t1; SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server ver: SERVER_VERSION, Binlog ver: 4 -master-bin.000001 106 Query 1 223 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB -master-bin.000001 223 Query 1 287 BEGIN -master-bin.000001 287 Table_map 1 330 table_id: # (test.t1) -master-bin.000001 330 Table_map 1 392 table_id: # (mysql.ndb_apply_status) -master-bin.000001 392 Write_rows 1 451 table_id: # -master-bin.000001 451 Write_rows 1 498 table_id: # flags: STMT_END_F -master-bin.000001 498 Query 1 563 COMMIT -master-bin.000001 563 Query 1 643 use `test`; TRUNCATE TABLE t1 -master-bin.000001 643 Query 1 719 use `test`; DROP TABLE t1 +master-bin.000001 4 Format_desc 1 107 Server ver: SERVER_VERSION, Binlog ver: 4 +master-bin.000001 107 Query 1 224 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB +master-bin.000001 224 Query 1 288 BEGIN +master-bin.000001 288 Table_map 1 331 table_id: # (test.t1) +master-bin.000001 331 Table_map 1 393 table_id: # (mysql.ndb_apply_status) +master-bin.000001 393 Write_rows 1 452 table_id: # +master-bin.000001 452 Write_rows 1 499 table_id: # flags: STMT_END_F +master-bin.000001 499 Query 1 564 COMMIT +master-bin.000001 564 Query 1 644 use `test`; TRUNCATE TABLE t1 +master-bin.000001 644 Query 1 720 use `test`; DROP TABLE t1 **** On Master **** CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB; INSERT INTO t1 VALUES (1,1), (2,2); @@ -65,27 +65,27 @@ a b DROP TABLE t1; SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server ver: SERVER_VERSION, Binlog ver: 4 -master-bin.000001 106 Query 1 223 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB -master-bin.000001 223 Query 1 287 BEGIN -master-bin.000001 287 Table_map 1 330 table_id: # (test.t1) -master-bin.000001 330 Table_map 1 392 table_id: # (mysql.ndb_apply_status) -master-bin.000001 392 Write_rows 1 451 table_id: # -master-bin.000001 451 Write_rows 1 498 table_id: # flags: STMT_END_F -master-bin.000001 498 Query 1 563 COMMIT -master-bin.000001 563 Query 1 643 use `test`; TRUNCATE TABLE t1 -master-bin.000001 643 Query 1 719 use `test`; DROP TABLE t1 -master-bin.000001 719 Query 1 836 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB -master-bin.000001 836 Query 1 900 BEGIN -master-bin.000001 900 Table_map 1 943 table_id: # (test.t1) -master-bin.000001 943 Table_map 1 1005 table_id: # (mysql.ndb_apply_status) -master-bin.000001 1005 Write_rows 1 1064 table_id: # -master-bin.000001 1064 Write_rows 1 1111 table_id: # flags: STMT_END_F -master-bin.000001 1111 Query 1 1176 COMMIT -master-bin.000001 1176 Query 1 1240 BEGIN -master-bin.000001 1240 Table_map 1 1283 table_id: # (test.t1) -master-bin.000001 1283 Table_map 1 1345 table_id: # (mysql.ndb_apply_status) -master-bin.000001 1345 Write_rows 1 1404 table_id: # -master-bin.000001 1404 Delete_rows 1 1443 table_id: # flags: STMT_END_F -master-bin.000001 1443 Query 1 1508 COMMIT -master-bin.000001 1508 Query 1 1584 use `test`; DROP TABLE t1 +master-bin.000001 4 Format_desc 1 107 Server ver: SERVER_VERSION, Binlog ver: 4 +master-bin.000001 107 Query 1 224 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB +master-bin.000001 224 Query 1 288 BEGIN +master-bin.000001 288 Table_map 1 331 table_id: # (test.t1) +master-bin.000001 331 Table_map 1 393 table_id: # (mysql.ndb_apply_status) +master-bin.000001 393 Write_rows 1 452 table_id: # +master-bin.000001 452 Write_rows 1 499 table_id: # flags: STMT_END_F +master-bin.000001 499 Query 1 564 COMMIT +master-bin.000001 564 Query 1 644 use `test`; TRUNCATE TABLE t1 +master-bin.000001 644 Query 1 720 use `test`; DROP TABLE t1 +master-bin.000001 720 Query 1 837 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB +master-bin.000001 837 Query 1 901 BEGIN +master-bin.000001 901 Table_map 1 944 table_id: # (test.t1) +master-bin.000001 944 Table_map 1 1006 table_id: # (mysql.ndb_apply_status) +master-bin.000001 1006 Write_rows 1 1065 table_id: # +master-bin.000001 1065 Write_rows 1 1112 table_id: # flags: STMT_END_F +master-bin.000001 1112 Query 1 1177 COMMIT +master-bin.000001 1177 Query 1 1241 BEGIN +master-bin.000001 1241 Table_map 1 1284 table_id: # (test.t1) +master-bin.000001 1284 Table_map 1 1346 table_id: # (mysql.ndb_apply_status) +master-bin.000001 1346 Write_rows 1 1405 table_id: # +master-bin.000001 1405 Delete_rows 1 1444 table_id: # flags: STMT_END_F +master-bin.000001 1444 Query 1 1509 COMMIT +master-bin.000001 1509 Query 1 1585 use `test`; DROP TABLE t1 diff --git a/mysql-test/t/ctype_cp932_binlog_stm.test b/mysql-test/t/ctype_cp932_binlog_stm.test index 89df33a6df5..19f44695f28 100644 --- a/mysql-test/t/ctype_cp932_binlog_stm.test +++ b/mysql-test/t/ctype_cp932_binlog_stm.test @@ -22,14 +22,14 @@ CALL bug18293("Foo's a Bar", _cp932 0xED40ED41ED42, 47.93)| SELECT HEX(s1),HEX(s2),d FROM t4| DROP PROCEDURE bug18293| DROP TABLE t4| -SHOW BINLOG EVENTS FROM 370| +SHOW BINLOG EVENTS FROM 371| delimiter ;| --echo End of 5.0 tests # # #28436: Incorrect position in SHOW BINLOG EVENTS causes server coredump -# Note: 364 is a magic position (found experimentally, depends on +# Note: 365 is a magic position (found experimentally, depends on # the log's contents) that caused the server crash. --error 1220 diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 7767abe43d0..597c9671053 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -71,7 +71,7 @@ select "--- --position --" as ""; --enable_query_log --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ ---exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --position=239 $MYSQLD_DATADIR/master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --position=240 $MYSQLD_DATADIR/master-bin.000002 # These are tests for remote binlog. # They should return the same as previous test. @@ -107,7 +107,7 @@ select "--- --position --" as ""; --enable_query_log --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ ---exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --read-from-remote-server --position=239 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --read-from-remote-server --position=240 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 # Bug#7853 mysqlbinlog does not accept input from stdin --disable_query_log @@ -119,7 +119,7 @@ select "--- reading stdin --" as ""; --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ ---exec $MYSQL_BINLOG --short-form --position=79 - < $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 +--exec $MYSQL_BINLOG --short-form --position=80 - < $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 drop table t1,t2; # diff --git a/mysql-test/t/mysqlbinlog2.test b/mysql-test/t/mysqlbinlog2.test index d6be029ea56..6089b83e42d 100644 --- a/mysql-test/t/mysqlbinlog2.test +++ b/mysql-test/t/mysqlbinlog2.test @@ -50,15 +50,15 @@ select "--- offset --" as ""; --disable_query_log select "--- start-position --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --start-position=608 $MYSQLD_DATADIR/master-bin.000001 +--exec $MYSQL_BINLOG --short-form --start-position=609 $MYSQLD_DATADIR/master-bin.000001 --disable_query_log select "--- stop-position --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --stop-position=608 $MYSQLD_DATADIR/master-bin.000001 +--exec $MYSQL_BINLOG --short-form --stop-position=609 $MYSQLD_DATADIR/master-bin.000001 --disable_query_log select "--- start and stop positions ---" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --start-position=608 --stop-position 725 $MYSQLD_DATADIR/master-bin.000001 +--exec $MYSQL_BINLOG --short-form --start-position=609 --stop-position 726 $MYSQLD_DATADIR/master-bin.000001 --disable_query_log select "--- start-datetime --" as ""; --enable_query_log @@ -84,11 +84,11 @@ select "--- offset --" as ""; --disable_query_log select "--- start-position --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --start-position=608 $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002 +--exec $MYSQL_BINLOG --short-form --start-position=609 $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002 --disable_query_log select "--- stop-position --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --stop-position=134 $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002 +--exec $MYSQL_BINLOG --short-form --stop-position=135 $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002 --disable_query_log select "--- start-datetime --" as ""; --enable_query_log @@ -111,15 +111,15 @@ select "--- offset --" as ""; --disable_query_log select "--- start-position --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --start-position=608 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 +--exec $MYSQL_BINLOG --short-form --start-position=609 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 --disable_query_log select "--- stop-position --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --stop-position=608 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 +--exec $MYSQL_BINLOG --short-form --stop-position=609 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 --disable_query_log select "--- start and stop positions ---" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --start-position=608 --stop-position 725 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 +--exec $MYSQL_BINLOG --short-form --start-position=609 --stop-position 726 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 --disable_query_log select "--- start-datetime --" as ""; --enable_query_log @@ -142,11 +142,11 @@ select "--- offset --" as ""; --disable_query_log select "--- start-position --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --start-position=608 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002 +--exec $MYSQL_BINLOG --short-form --start-position=609 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002 --disable_query_log select "--- stop-position --" as ""; --enable_query_log ---exec $MYSQL_BINLOG --short-form --stop-position=134 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002 +--exec $MYSQL_BINLOG --short-form --stop-position=135 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002 --disable_query_log select "--- start-datetime --" as ""; --enable_query_log diff --git a/mysql-test/t/sp_trans_log.test b/mysql-test/t/sp_trans_log.test index 2f2b84a9bef..68467f71ee1 100644 --- a/mysql-test/t/sp_trans_log.test +++ b/mysql-test/t/sp_trans_log.test @@ -35,7 +35,8 @@ reset master| --error ER_DUP_ENTRY insert into t2 values (bug23333(),1)| --replace_column 2 # 5 # 6 # -show binlog events from 106 /* with fixes for #23333 will show there is the query */| +# the following must show there is (are) events after the query */ +source include/show_binlog_events.inc| select count(*),@a from t1 /* must be 1,1 */| delimiter ;| diff --git a/sql/lex.h b/sql/lex.h index b199a79350b..790808a8c14 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -323,6 +323,7 @@ static SYMBOL symbols[] = { { "MASTER_SSL_KEY", SYM(MASTER_SSL_KEY_SYM)}, { "MASTER_SSL_VERIFY_SERVER_CERT", SYM(MASTER_SSL_VERIFY_SERVER_CERT_SYM)}, { "MASTER_USER", SYM(MASTER_USER_SYM)}, + { "MASTER_HEARTBEAT_PERIOD", SYM(MASTER_HEARTBEAT_PERIOD_SYM)}, { "MATCH", SYM(MATCH)}, { "MAX_CONNECTIONS_PER_HOUR", SYM(MAX_CONNECTIONS_PER_HOUR)}, { "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR)}, diff --git a/sql/log.cc b/sql/log.cc index 1af2f3a4ddc..362df871ba9 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2413,7 +2413,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name, MYSQL_BIN_LOG::MYSQL_BIN_LOG() :bytes_written(0), prepared_xids(0), file_id(1), open_count(1), need_start_event(TRUE), m_table_map_version(0), - is_relay_log(0), + is_relay_log(0), signal_cnt(0), description_event_for_exec(0), description_event_for_queue(0) { /* @@ -4605,12 +4605,9 @@ err: /** - Wait until we get a signal that the binary log has been updated. + Wait until we get a signal that the relay log has been updated. @param thd Thread variable - @param is_slave If 0, the caller is the Binlog_dump thread from master; - if 1, the caller is the SQL thread from the slave. This - influences only thd->proc_info. @note One must have a lock on LOCK_log before calling this function. @@ -4618,22 +4615,53 @@ err: THD::enter_cond() (see NOTES in sql_class.h). */ -void MYSQL_BIN_LOG::wait_for_update(THD* thd, bool is_slave) +void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd) { const char *old_msg; - DBUG_ENTER("wait_for_update"); + DBUG_ENTER("wait_for_update_relay_log"); old_msg= thd->enter_cond(&update_cond, &LOCK_log, - is_slave ? - "Has read all relay log; waiting for the slave I/O " - "thread to update it" : - "Has sent all binlog to slave; waiting for binlog " - "to be updated"); + "Slave has read all relay log; " + "waiting for the slave I/O " + "thread to update it" ); pthread_cond_wait(&update_cond, &LOCK_log); thd->exit_cond(old_msg); DBUG_VOID_RETURN; } +/** + Wait until we get a signal that the binary log has been updated. + Applies to master only. + + NOTES + @param[in] thd a THD struct + @param[in] timeout a pointer to a timespec; + NULL means to wait w/o timeout. + @retval 0 if got signalled on update + @retval non-0 if wait timeout elapsed + @note + LOCK_log must be taken before calling this function. + LOCK_log is being released while the thread is waiting. + LOCK_log is released by the caller. +*/ + +int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd, + const struct timespec *timeout) +{ + int ret= 0; + const char* old_msg = thd->proc_info; + DBUG_ENTER("wait_for_update_bin_log"); + old_msg= thd->enter_cond(&update_cond, &LOCK_log, + "Master has sent all binlog to slave; " + "waiting for binlog to be updated"); + if (!timeout) + pthread_cond_wait(&update_cond, &LOCK_log); + else + ret= pthread_cond_timedwait(&update_cond, &LOCK_log, + const_cast(timeout)); + DBUG_RETURN(ret); +} + /** Close the log file. @@ -4846,6 +4874,7 @@ bool flush_error_log() void MYSQL_BIN_LOG::signal_update() { DBUG_ENTER("MYSQL_BIN_LOG::signal_update"); + signal_cnt++; pthread_cond_broadcast(&update_cond); DBUG_VOID_RETURN; } diff --git a/sql/log.h b/sql/log.h index d306d6f7182..8d6a90d8a35 100644 --- a/sql/log.h +++ b/sql/log.h @@ -284,7 +284,7 @@ public: /* This is relay log */ bool is_relay_log; - + ulong signal_cnt; // update of the counter is checked by heartbeat /* These describe the log's format. This is used only for relay logs. _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's @@ -339,7 +339,8 @@ public: } void set_max_size(ulong max_size_arg); void signal_update(); - void wait_for_update(THD* thd, bool master_or_slave); + void wait_for_update_relay_log(THD* thd); + int wait_for_update_bin_log(THD* thd, const struct timespec * timeout); void set_need_start_event() { need_start_event = 1; } void init(bool no_auto_events_arg, ulong max_size); void init_pthread_objects(); diff --git a/sql/log_event.cc b/sql/log_event.cc index fb6a5230fda..6c240735d23 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3643,6 +3643,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) post_header_len[UPDATE_ROWS_EVENT-1]= post_header_len[DELETE_ROWS_EVENT-1]= 6;); post_header_len[INCIDENT_EVENT-1]= INCIDENT_HEADER_LEN; + post_header_len[HEARTBEAT_LOG_EVENT-1]= 0; // Sanity-check that all post header lengths are initialized. IF_DBUG({ @@ -9427,3 +9428,16 @@ st_print_event_info::st_print_event_info() open_cached_file(&body_cache, NULL, NULL, 0, flags); } #endif + + +#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) +Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len, + const Format_description_log_event* description_event) + :Log_event(buf, description_event) +{ + uint8 header_size= description_event->common_header_len; + ident_len = event_len - header_size; + set_if_smaller(ident_len,FN_REFLEN-1); + log_ident= buf + header_size; +} +#endif diff --git a/sql/log_event.h b/sql/log_event.h index 8202dddcc76..b481ae59502 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -250,6 +250,7 @@ struct sql_ex_info #define EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN (4 + 4 + 4 + 1) #define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN) #define INCIDENT_HEADER_LEN 2 +#define HEARTBEAT_HEADER_LEN 0 /* Max number of possible extra bytes in a replication event compared to a packet (i.e. a query) sent from client to master; @@ -574,6 +575,12 @@ enum Log_event_type */ INCIDENT_EVENT= 26, + /* + Heartbeat event to be send by master at its idle time + to ensure master's online status to slave + */ + HEARTBEAT_LOG_EVENT= 27, + /* Add new events here - right above this comment! Existing events (except ENUM_END_EVENT) should never change their numbers @@ -689,6 +696,20 @@ typedef struct st_print_event_info } PRINT_EVENT_INFO; #endif +/** + the struct aggregates two paramenters that identify an event + uniquely in scope of communication of a particular master and slave couple. + I.e there can not be 2 events from the same staying connected master which + have the same coordinates. + @note + Such identifier is not yet unique generally as the event originating master + is resetable. Also the crashed master can be replaced with some other. +*/ +struct event_coordinates +{ + char * file_name; // binlog file name (directories stripped) + my_off_t pos; // event's position in the binlog file +}; /** @class Log_event @@ -3916,6 +3937,42 @@ static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE); } +#ifndef MYSQL_CLIENT +/***************************************************************************** + + Heartbeat Log Event class + + Replication event to ensure to slave that master is alive. + The event is originated by master's dump thread and sent straight to + slave without being logged. Slave itself does not store it in relay log + but rather uses a data for immediate checks and throws away the event. + + Two members of the class log_ident and Log_event::log_pos comprise + @see the event_coordinates instance. The coordinates that a heartbeat + instance carries correspond to the last event master has sent from + its binlog. + + ****************************************************************************/ +class Heartbeat_log_event: public Log_event +{ +public: + Heartbeat_log_event(const char* buf, uint event_len, + const Format_description_log_event* description_event); + Log_event_type get_type_code() { return HEARTBEAT_LOG_EVENT; } + bool is_valid() const + { + return (log_ident != NULL && + log_pos >= BIN_LOG_HEADER_SIZE); + } + const char * get_log_ident() { return log_ident; } + uint get_ident_len() { return ident_len; } + +private: + const char* log_ident; + uint ident_len; +}; +#endif + /** @} (end of group Replication) */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7e9eb6e7291..4bbb49f47ff 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7068,6 +7068,40 @@ static int show_slave_retried_trans(THD *thd, SHOW_VAR *var, char *buff) pthread_mutex_unlock(&LOCK_active_mi); return 0; } + +static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff) +{ + pthread_mutex_lock(&LOCK_active_mi); + if (active_mi) + { + var->type= SHOW_LONGLONG; + var->value= buff; + pthread_mutex_lock(&active_mi->rli.data_lock); + *((longlong *)buff)= active_mi->received_heartbeats; + pthread_mutex_unlock(&active_mi->rli.data_lock); + } + else + var->type= SHOW_UNDEF; + pthread_mutex_unlock(&LOCK_active_mi); + return 0; +} + +static int show_heartbeat_period(THD *thd, SHOW_VAR *var, char *buff) +{ + pthread_mutex_lock(&LOCK_active_mi); + if (active_mi) + { + var->type= SHOW_CHAR; + var->value= buff; + my_sprintf(buff, (buff, "%.3f",active_mi->heartbeat_period)); + } + else + var->type= SHOW_UNDEF; + pthread_mutex_unlock(&LOCK_active_mi); + return 0; +} + + #endif /* HAVE_REPLICATION */ static int show_open_tables(THD *thd, SHOW_VAR *var, char *buff) @@ -7432,6 +7466,8 @@ SHOW_VAR status_vars[]= { {"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_LONG}, #ifdef HAVE_REPLICATION {"Slave_retried_transactions",(char*) &show_slave_retried_trans, SHOW_FUNC}, + {"Slave_heartbeat_period", (char*) &show_heartbeat_period, SHOW_FUNC}, + {"Slave_received_heartbeats",(char*) &show_slave_received_heartbeats, SHOW_FUNC}, {"Slave_running", (char*) &show_slave_running, SHOW_FUNC}, #endif {"Slow_launch_threads", (char*) &slow_launch_threads, SHOW_LONG}, diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 5e46837e948..77f7b7e1929 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -26,12 +26,13 @@ int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val); +int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val); Master_info::Master_info() :Slave_reporting_capability("I/O"), ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), inited(0), - abort_slave(0),slave_running(0), - slave_run_id(0) + abort_slave(0),slave_running(0), slave_run_id(0), + heartbeat_period(0), received_heartbeats(0) { host[0] = 0; user[0] = 0; password[0] = 0; ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; @@ -84,6 +85,17 @@ void init_master_info_with_options(Master_info* mi) strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1); /* Intentionally init ssl_verify_server_cert to 0, no option available */ mi->ssl_verify_server_cert= 0; + /* + always request heartbeat unless master_heartbeat_period is set + explicitly zero. Here is the default value for heartbeat period + if CHANGE MASTER did not specify it. (no data loss in conversion + as hb period has a max) + */ + mi->heartbeat_period= (float) min(SLAVE_MAX_HEARTBEAT_PERIOD, + (slave_net_timeout/2.0)); + DBUG_ASSERT(mi->heartbeat_period > (float) 0.001 + || mi->heartbeat_period == 0); + DBUG_VOID_RETURN; } @@ -94,8 +106,11 @@ enum { /* 5.1.16 added value of master_ssl_verify_server_cert */ LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15, + /* 6.0 added value of master_heartbeat_period */ + LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16, + /* Number of lines currently used when saving master info file */ - LINES_IN_MASTER_INFO= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT + LINES_IN_MASTER_INFO= LINE_FOR_MASTER_HEARTBEAT_PERIOD }; int init_master_info(Master_info* mi, const char* master_info_fname, @@ -197,6 +212,7 @@ file '%s')", fname); mi->fd = fd; int port, connect_retry, master_log_pos, lines; int ssl= 0, ssl_verify_server_cert= 0; + float master_heartbeat_period= 0.0; char *first_non_digit; /* @@ -281,7 +297,13 @@ file '%s')", fname); if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT && init_intvar_from_file(&ssl_verify_server_cert, &mi->file, 0)) goto errwithmsg; - + /* + Starting from 6.0 master_heartbeat_period might be + in the file + */ + if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD && + init_floatvar_from_file(&master_heartbeat_period, &mi->file, 0.0)) + goto errwithmsg; } #ifndef HAVE_OPENSSL @@ -300,6 +322,7 @@ file '%s')", fname); mi->connect_retry= (uint) connect_retry; mi->ssl= (my_bool) ssl; mi->ssl_verify_server_cert= ssl_verify_server_cert; + mi->heartbeat_period= master_heartbeat_period; } DBUG_PRINT("master_info",("log_file_name: %s position: %ld", mi->master_log_name, @@ -378,16 +401,18 @@ int flush_master_info(Master_info* mi, bool flush_relay_log_cache) contents of file). But because of number of lines in the first line of file we don't care about this garbage. */ - + char heartbeat_buf[sizeof(mi->heartbeat_period) * 4]; // buffer to suffice always + my_sprintf(heartbeat_buf, (heartbeat_buf, "%.3f", mi->heartbeat_period)); my_b_seek(file, 0L); my_b_printf(file, - "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n", + "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n", LINES_IN_MASTER_INFO, mi->master_log_name, llstr(mi->master_log_pos, lbuf), mi->host, mi->user, mi->password, mi->port, mi->connect_retry, (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, - mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert); + mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert, + heartbeat_buf); DBUG_RETURN(-flush_io_cache(file)); } diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index 93fb0a98198..35e18414932 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -83,6 +83,8 @@ class Master_info : public Slave_reporting_capability Relay_log_info rli; uint port; uint connect_retry; + float heartbeat_period; // interface with CHANGE MASTER or master.info + ulonglong received_heartbeats; // counter of received heartbeat events #ifndef DBUG_OFF int events_till_disconnect; #endif diff --git a/sql/slave.cc b/sql/slave.cc index fac9ee214c5..4a161a345eb 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -770,7 +770,6 @@ static bool sql_slave_killed(THD* thd, Relay_log_info* rli) DBUG_RETURN(0); } - /* skip_load_data_infile() @@ -860,6 +859,37 @@ int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) DBUG_RETURN(1); } +int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val) +{ + char buf[16]; + DBUG_ENTER("init_floatvar_from_file"); + + + if (my_b_gets(f, buf, sizeof(buf))) + { + if (sscanf(buf, "%f", var) != 1) + DBUG_RETURN(1); + else + DBUG_RETURN(0); + } + else if (default_val != 0.0) + { + *var = default_val; + DBUG_RETURN(0); + } + DBUG_RETURN(1); +} + +static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info) +{ + if (io_slave_killed(thd, mi)) + { + if (info && global_system_variables.log_warnings) + sql_print_information(info); + return TRUE; + } + return FALSE; +} /* Check if the error is caused by network. @@ -1189,6 +1219,32 @@ when it try to get the value of TIME_ZONE global variable from master."; } } + if (mi->heartbeat_period != 0.0) + { + char llbuf[22]; + const char query_format[]= "SET @master_heartbeat_period= %s"; + char query[sizeof(query_format) - 2 + sizeof(llbuf)]; + /* + the period is an ulonglong of nano-secs. + */ + llstr((ulonglong) (mi->heartbeat_period*1000000000UL), llbuf); + my_sprintf(query, (query, query_format, llbuf)); + + if (mysql_real_query(mysql, query, strlen(query)) + && !check_io_slave_killed(mi->io_thd, mi, NULL)) + { + errmsg= "The slave I/O thread stops because querying master with '%s' " + "failed; error: '%s' "; + err_code= ER_SLAVE_FATAL_ERROR; + sprintf(err_buff, "%s Error: %s", errmsg, + query, mysql_error(mysql)); + mysql_free_result(mysql_store_result(mysql)); + goto err; + } + mysql_free_result(mysql_store_result(mysql)); + } + + err: if (errmsg) { @@ -2381,18 +2437,6 @@ on this slave.\ } -static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info) -{ - if (io_slave_killed(thd, mi)) - { - if (info && global_system_variables.log_warnings) - sql_print_information(info); - return TRUE; - } - return FALSE; -} - - /** @brief Try to reconnect slave IO thread. @@ -3552,6 +3596,7 @@ static int queue_old_event(Master_info *mi, const char *buf, static int queue_event(Master_info* mi,const char* buf, ulong event_len) { int error= 0; + String error_msg; ulong inc_pos; Relay_log_info *rli= &mi->rli; pthread_mutex_t *log_lock= rli->relay_log.get_log_lock(); @@ -3586,7 +3631,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) Rotate_log_event rev(buf,event_len,mi->rli.relay_log.description_event_for_queue); if (unlikely(process_io_rotate(mi,&rev))) { - error= 1; + error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE; goto err; } /* @@ -3613,7 +3658,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) Log_event::read_log_event(buf, event_len, &errmsg, mi->rli.relay_log.description_event_for_queue))) { - error= 2; + error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE; goto err; } delete mi->rli.relay_log.description_event_for_queue; @@ -3632,6 +3677,56 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) } break; + + case HEARTBEAT_LOG_EVENT: + { + /* + HB (heartbeat) cannot come before RL (Relay) + */ + char llbuf[22]; + Heartbeat_log_event hb(buf, event_len, mi->rli.relay_log.description_event_for_queue); + if (!hb.is_valid()) + { + error= ER_SLAVE_HEARTBEAT_FAILURE; + error_msg.append(STRING_WITH_LEN("inconsistent heartbeat event content;")); + error_msg.append(STRING_WITH_LEN("the event's data: log_file_name ")); + error_msg.append(hb.get_log_ident(), (uint) strlen(hb.get_log_ident())); + error_msg.append(STRING_WITH_LEN(" log_pos ")); + llstr(hb.log_pos, llbuf); + error_msg.append(llbuf, strlen(llbuf)); + goto err; + } + mi->received_heartbeats++; + /* + compare local and event's versions of log_file, log_pos. + + Heartbeat is sent only after an event corresponding to the corrdinates + the heartbeat carries. + Slave can not have a difference in coordinates except in the only + special case when mi->master_log_name, master_log_pos have never + been updated by Rotate event i.e when slave does not have any history + with the master (and thereafter mi->master_log_pos is NULL). + + TODO: handling `when' for SHOW SLAVE STATUS' snds behind + */ + if ((memcmp(mi->master_log_name, hb.get_log_ident(), hb.get_ident_len()) + && mi->master_log_name != NULL) + || mi->master_log_pos != hb.log_pos) + { + /* missed events of heartbeat from the past */ + error= ER_SLAVE_HEARTBEAT_FAILURE; + error_msg.append(STRING_WITH_LEN("heartbeat is not compatible with local info;")); + error_msg.append(STRING_WITH_LEN("the event's data: log_file_name ")); + error_msg.append(hb.get_log_ident(), (uint) strlen(hb.get_log_ident())); + error_msg.append(STRING_WITH_LEN(" log_pos ")); + llstr(hb.log_pos, llbuf); + error_msg.append(llbuf, strlen(llbuf)); + goto err; + } + goto skip_relay_logging; + } + break; + default: inc_pos= event_len; break; @@ -3692,15 +3787,23 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) rli->relay_log.harvest_bytes_written(&rli->log_space_total); } else - error= 3; + { + error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE; + } rli->ign_master_log_name_end[0]= 0; // last event is not ignored } pthread_mutex_unlock(log_lock); - +skip_relay_logging: + err: pthread_mutex_unlock(&mi->data_lock); DBUG_PRINT("info", ("error: %d", error)); + if (error) + mi->report(ERROR_LEVEL, error, ER(error), + (error == ER_SLAVE_RELAY_LOG_WRITE_FAILURE)? + "could not queue event from master" : + error_msg.ptr()); DBUG_RETURN(error); } @@ -4208,8 +4311,8 @@ static Log_event* next_event(Relay_log_info* rli) */ pthread_mutex_unlock(&rli->log_space_lock); pthread_cond_broadcast(&rli->log_space_cond); - // Note that wait_for_update unlocks lock_log ! - rli->relay_log.wait_for_update(rli->sql_thd, 1); + // 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 pthread_mutex_lock(&rli->data_lock); rli->last_master_timestamp= save_timestamp; diff --git a/sql/slave.h b/sql/slave.h index a44a7eed83e..e8364090eb4 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -22,6 +22,17 @@ @file */ + +/** + Some of defines are need in parser even though replication is not + compiled in (embedded). +*/ + +/** + The maximum is defined as (ULONG_MAX/1000) with 4 bytes ulong +*/ +#define SLAVE_MAX_HEARTBEAT_PERIOD 4294967 + #ifdef HAVE_REPLICATION #include "log.h" @@ -33,7 +44,6 @@ #define MAX_SLAVE_ERROR 2000 - // Forward declarations class Relay_log_info; class Master_info; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6f9f667a75a..f6effab93a4 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -206,14 +206,15 @@ typedef struct st_lex_master_info { char *host, *user, *password, *log_file_name; uint port, connect_retry; + float heartbeat_period; ulonglong pos; ulong server_id; /* Enum is used for making it possible to detect if the user changed variable or if it should be left at old value */ - enum {SSL_UNCHANGED, SSL_DISABLE, SSL_ENABLE} - ssl, ssl_verify_server_cert; + enum {LEX_MI_UNCHANGED, LEX_MI_DISABLE, LEX_MI_ENABLE} + ssl, ssl_verify_server_cert, heartbeat_opt; char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher; char *relay_log_name; ulong relay_log_pos; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 0ec8d91214c..cde713b1b40 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -336,6 +336,74 @@ Increase max_allowed_packet on master"; } +/** + An auxiliary function for calling in mysql_binlog_send + to initialize the heartbeat timeout in waiting for a binlogged event. + + @param[in] thd THD to access a user variable + + @return heartbeat period an ulonglong of nanoseconds + or zero if heartbeat was not demanded by slave +*/ +static ulonglong get_heartbeat_period(THD * thd) +{ + my_bool null_value; + LEX_STRING name= { C_STRING_WITH_LEN("master_heartbeat_period")}; + user_var_entry *entry= + (user_var_entry*) hash_search(&thd->user_vars, (uchar*) name.str, + name.length); + return entry? entry->val_int(&null_value) : 0; +} + +/* + Function prepares and sends repliation heartbeat event. + + @param net net object of THD + @param packet buffer to store the heartbeat instance + @param event_coordinates binlog file name and position of the last + real event master sent from binlog + + @note + Among three essential pieces of heartbeat data Log_event::when + is computed locally. + The error to send is serious and should force terminating + the dump thread. +*/ +static int send_heartbeat_event(NET* net, String* packet, + const struct event_coordinates *coord) +{ + DBUG_ENTER("send_heartbeat_event"); + char header[LOG_EVENT_HEADER_LEN]; + /* + 'when' (the timestamp) is set to 0 so that slave could distinguish between + real and fake Rotate events (if necessary) + */ + memset(header, 0, 4); // when + + header[EVENT_TYPE_OFFSET] = HEARTBEAT_LOG_EVENT; + + char* p= coord->file_name + dirname_length(coord->file_name); + + uint ident_len = strlen(p); + ulong event_len = ident_len + LOG_EVENT_HEADER_LEN; + int4store(header + SERVER_ID_OFFSET, server_id); + int4store(header + EVENT_LEN_OFFSET, event_len); + int2store(header + FLAGS_OFFSET, 0); + + int4store(header + LOG_POS_OFFSET, coord->pos); // log_pos + + packet->append(header, sizeof(header)); + packet->append(p, ident_len); // log_file_name + + if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) || + net_flush(net)) + { + DBUG_RETURN(-1); + } + packet->set("\0", 1, &my_charset_bin); + DBUG_RETURN(0); +} + /* TODO: Clean up loop to only have one call to send_file() */ @@ -361,7 +429,22 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, DBUG_PRINT("enter",("log_ident: '%s' pos: %ld", log_ident, (long) pos)); bzero((char*) &log,sizeof(log)); - + /* + heartbeat_period from @master_heartbeat_period user variable + */ + ulonglong heartbeat_period= get_heartbeat_period(thd); + struct timespec heartbeat_buf; + struct event_coordinates coord_buf; + struct timespec *heartbeat_ts= NULL; + struct event_coordinates *coord= NULL; + if (heartbeat_period != LL(0)) + { + heartbeat_ts= &heartbeat_buf; + set_timespec_nsec(*heartbeat_ts, 0); + coord= &coord_buf; + coord->file_name= log_file_name; // initialization basing on what slave remembers + coord->pos= pos; + } #ifndef DBUG_OFF if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2)) { @@ -555,6 +638,11 @@ impossible position"; goto err; } #endif + /* + log's filename does not change while it's active + */ + if (coord) + coord->pos= uint4korr(packet->ptr() + 1 + LOG_POS_OFFSET); if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT) { @@ -650,26 +738,65 @@ impossible position"; /* we read successfully, so we'll need to send it to the slave */ pthread_mutex_unlock(log_lock); read_packet = 1; + if (coord) + coord->pos= uint4korr(packet->ptr() + 1 + LOG_POS_OFFSET); break; case LOG_READ_EOF: + { + int ret; + ulong signal_cnt; DBUG_PRINT("wait",("waiting for data in binary log")); if (thd->server_id==0) // for mysqlbinlog (mysqlbinlog.server_id==0) { pthread_mutex_unlock(log_lock); goto end; } - if (!thd->killed) - { - /* Note that the following call unlocks lock_log */ - mysql_bin_log.wait_for_update(thd, 0); - } - else - pthread_mutex_unlock(log_lock); - DBUG_PRINT("wait",("binary log received update")); - break; - default: +#ifndef DBUG_OFF + ulong hb_info_counter= 0; +#endif + signal_cnt= mysql_bin_log.signal_cnt; + do + { + if (coord) + { + DBUG_ASSERT(heartbeat_ts && heartbeat_period != LL(0)); + set_timespec_nsec(*heartbeat_ts, heartbeat_period); + } + ret= mysql_bin_log.wait_for_update_bin_log(thd, heartbeat_ts); + DBUG_ASSERT(ret == 0 || heartbeat_period != LL(0) && coord != NULL); + if (ret == ETIMEDOUT || ret == ETIME) + { +#ifndef DBUG_OFF + if (hb_info_counter < 3) + { + sql_print_information("master sends heartbeat message"); + hb_info_counter++; + if (hb_info_counter == 3) + sql_print_information("the rest of heartbeat info skipped ..."); + } +#endif + if (send_heartbeat_event(net, packet, coord)) + { + errmsg = "Failed on my_net_write()"; + my_errno= ER_UNKNOWN_ERROR; + pthread_mutex_unlock(log_lock); + goto err; + } + } + else + { + DBUG_ASSERT(ret == 0 && signal_cnt != mysql_bin_log.signal_cnt || + thd->killed); + DBUG_PRINT("wait",("binary log received update")); + } + } while (signal_cnt == mysql_bin_log.signal_cnt && !thd->killed); + pthread_mutex_unlock(log_lock); + } + break; + + default: pthread_mutex_unlock(log_lock); fatal_error = 1; break; @@ -753,6 +880,8 @@ impossible position"; packet->length(0); packet->append('\0'); + if (coord) + coord->file_name= log_file_name; // reset to the next } } @@ -1195,13 +1324,18 @@ bool change_master(THD* thd, Master_info* mi) mi->port = lex_mi->port; if (lex_mi->connect_retry) mi->connect_retry = lex_mi->connect_retry; + if (lex_mi->heartbeat_opt != LEX_MASTER_INFO::LEX_MI_UNCHANGED) + mi->heartbeat_period = lex_mi->heartbeat_period; + else + mi->heartbeat_period= (float) min(SLAVE_MAX_HEARTBEAT_PERIOD, + (slave_net_timeout/2.0)); + mi->received_heartbeats= LL(0); // counter lives until master is CHANGEd + if (lex_mi->ssl != LEX_MASTER_INFO::LEX_MI_UNCHANGED) + mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE); - if (lex_mi->ssl != LEX_MASTER_INFO::SSL_UNCHANGED) - mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::SSL_ENABLE); - - if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::SSL_UNCHANGED) + if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::LEX_MI_UNCHANGED) mi->ssl_verify_server_cert= - (lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::SSL_ENABLE); + (lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::LEX_MI_ENABLE); if (lex_mi->ssl_ca) strmake(mi->ssl_ca, lex_mi->ssl_ca, sizeof(mi->ssl_ca)-1); @@ -1745,6 +1879,26 @@ public: bool update(THD *thd, set_var *var); }; +static void fix_slave_net_timeout(THD *thd, enum_var_type type) +{ + DBUG_ENTER("fix_slave_net_timeout"); +#ifdef HAVE_REPLICATION + pthread_mutex_lock(&LOCK_active_mi); + DBUG_PRINT("info",("slave_net_timeout=%lu mi->heartbeat_period=%.3f", + slave_net_timeout, + (active_mi? active_mi->heartbeat_period : 0.0))); + if (active_mi && slave_net_timeout < active_mi->heartbeat_period) + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, + "The currect value for master_heartbeat_period" + " exceeds the new value of `slave_net_timeout' sec." + " A sensible value for the period should be" + " less than the timeout."); + pthread_mutex_unlock(&LOCK_active_mi); +#endif + DBUG_VOID_RETURN; +} + static sys_var_chain vars = { NULL, NULL }; static sys_var_const sys_log_slave_updates(&vars, "log_slave_updates", @@ -1770,7 +1924,8 @@ static sys_var_const sys_slave_load_tmpdir(&vars, "slave_load_tmpdir", OPT_GLOBAL, SHOW_CHAR_PTR, (uchar*) &slave_load_tmpdir); static sys_var_long_ptr sys_slave_net_timeout(&vars, "slave_net_timeout", - &slave_net_timeout); + &slave_net_timeout, + fix_slave_net_timeout); static sys_var_const sys_slave_skip_errors(&vars, "slave_skip_errors", OPT_GLOBAL, SHOW_CHAR, (uchar*) slave_skip_error_names); @@ -1835,6 +1990,7 @@ int init_replication_sys_vars() return 0; } + #endif /* HAVE_REPLICATION */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a18f57bf9cf..50395d386e8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -814,6 +814,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token MASTER_SSL_VERIFY_SERVER_CERT_SYM %token MASTER_SYM %token MASTER_USER_SYM +%token MASTER_HEARTBEAT_PERIOD_SYM %token MATCH /* SQL-2003-R */ %token MAX_CONNECTIONS_PER_HOUR %token MAX_QUERIES_PER_HOUR @@ -1592,7 +1593,7 @@ master_def: | MASTER_SSL_SYM EQ ulong_num { Lex->mi.ssl= $3 ? - LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE; + LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE; } | MASTER_SSL_CA_SYM EQ TEXT_STRING_sys { @@ -1617,9 +1618,51 @@ master_def: | MASTER_SSL_VERIFY_SERVER_CERT_SYM EQ ulong_num { Lex->mi.ssl_verify_server_cert= $3 ? - LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE; + LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE; } - | master_file_def + + | MASTER_HEARTBEAT_PERIOD_SYM EQ NUM_literal + { + Lex->mi.heartbeat_period= (float) $3->val_real(); + if (Lex->mi.heartbeat_period > SLAVE_MAX_HEARTBEAT_PERIOD || + Lex->mi.heartbeat_period < 0.0) + { + const char format[]= "%d seconds"; + char buf[4*sizeof(SLAVE_MAX_HEARTBEAT_PERIOD) + sizeof(format)]; + my_sprintf(buf, (buf, format, SLAVE_MAX_HEARTBEAT_PERIOD)); + my_error(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, + MYF(0), + " is negative or exceeds the maximum ", + buf); + MYSQL_YYABORT; + } + if (Lex->mi.heartbeat_period > slave_net_timeout) + { + push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, + ER(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE), + " exceeds the value of `slave_net_timeout' sec.", + " A sensible value for the period should be" + " less than the timeout."); + } + if (Lex->mi.heartbeat_period < 0.001) + { + if (Lex->mi.heartbeat_period != 0.0) + { + push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, + ER(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE), + " is less than 1 msec.", + " The period is reset to zero which means" + " no heartbeats will be sending"); + Lex->mi.heartbeat_period= 0.0; + } + Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_DISABLE; + } + Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; + } + | + master_file_def ; master_file_def: From f6a8698a54c30ffd61f5aef40018d36258771ea5 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Tue, 29 Sep 2009 14:18:41 +0300 Subject: [PATCH 024/274] WL#342 heartbeat Backporting the basic tests --- mysql-test/suite/rpl/r/rpl_heartbeat.result | 139 ++++++++++++++++ mysql-test/suite/rpl/t/rpl_heartbeat.test | 166 ++++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 mysql-test/suite/rpl/r/rpl_heartbeat.result create mode 100644 mysql-test/suite/rpl/t/rpl_heartbeat.test diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat.result b/mysql-test/suite/rpl/r/rpl_heartbeat.result new file mode 100644 index 00000000000..5775351c33d --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_heartbeat.result @@ -0,0 +1,139 @@ +reset master; +set @@global.slave_net_timeout= 10; +Warnings: +Warning 1624 The currect value for master_heartbeat_period exceeds the new value of `slave_net_timeout' sec. A sensible value for the period should be less than the timeout. +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root'; +show status like 'Slave_heartbeat_period';; +Variable_name Slave_heartbeat_period +Value 5.000 +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 4294968; +ERROR HY000: The requested value for the heartbeat period is negative or exceeds the maximum 4294967 seconds +show status like 'Slave_heartbeat_period';; +Variable_name Slave_heartbeat_period +Value 5.000 +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 0.0009999; +Warnings: +Warning 1624 The requested value for the heartbeat period is less than 1 msec. The period is reset to zero which means no heartbeats will be sending +show status like 'Slave_heartbeat_period';; +Variable_name Slave_heartbeat_period +Value 0.000 +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 4294967; +Warnings: +Warning 1624 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' sec. A sensible value for the period should be less than the timeout. +show status like 'Slave_heartbeat_period';; +Variable_name Slave_heartbeat_period +Value 4294967.000 +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 0.001; +show status like 'Slave_heartbeat_period';; +Variable_name Slave_heartbeat_period +Value 0.001 +reset slave; +set @@global.slave_net_timeout= 5; +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 5.001; +Warnings: +Warning 1624 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' sec. A sensible value for the period should be less than the timeout. +show status like 'Slave_heartbeat_period';; +Variable_name Slave_heartbeat_period +Value 5.001 +reset slave; +set @@global.slave_net_timeout= 5; +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 4; +show status like 'Slave_heartbeat_period';; +Variable_name Slave_heartbeat_period +Value 4.000 +set @@global.slave_net_timeout= 3 /* must be a warning */; +Warnings: +Warning 1624 The currect value for master_heartbeat_period exceeds the new value of `slave_net_timeout' sec. A sensible value for the period should be less than the timeout. +reset slave; +drop table if exists t1; +set @@global.slave_net_timeout= 10; +change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 0.5; +show status like 'Slave_heartbeat_period';; +Variable_name Slave_heartbeat_period +Value 0.500 +start slave; +create table t1 (f1 int); +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 280 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table # +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 280 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 0 +Last_SQL_Error +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 280 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table # +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 280 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 0 +Last_SQL_Error +show status like 'Slave_heartbeat_period';; +Variable_name Slave_heartbeat_period +Value 0.500 +A heartbeat has been received by the slave +drop table t1; +End of tests diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat.test b/mysql-test/suite/rpl/t/rpl_heartbeat.test new file mode 100644 index 00000000000..4304888d6a5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat.test @@ -0,0 +1,166 @@ +# Testing master to slave heartbeat protocol +# +# Including: +# - user interface, grammar, checking the range and warnings about +# unreasonable values for the heartbeat period; +# - no rotation of relay log if heartbeat is less that slave_net_timeout +# - SHOW STATUS like 'Slave_received_heartbeats' action +# - SHOW STATUS like 'Slave_heartbeat_period' report + +-- source include/have_log_bin.inc + +connect (master,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); +connect (slave,localhost,root,,test,$SLAVE_MYPORT,$SLAVE_MYSOCK); + +connection master; +reset master; + +connection slave; +set @@global.slave_net_timeout= 10; + +### +### Checking the range +### + +# +# default period slave_net_timeout/2 +# +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; +--query_vertical show status like 'Slave_heartbeat_period'; + +# +# the max for the period is ULONG_MAX/1000; an attempt to exceed it is denied +# +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4294968; +--query_vertical show status like 'Slave_heartbeat_period'; + +# +# the min value for the period is 1 millisecond an attempt to assign a +# lesser will be warned with treating the value as zero +# +connection slave; +--replace_result $MASTER_MYPORT MASTER_PORT +### 5.1 mtr does not have --warning ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.0009999; +--query_vertical show status like 'Slave_heartbeat_period'; + +# +# the actual max and min must be accepted +# +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4294967; +--query_vertical show status like 'Slave_heartbeat_period'; + +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.001; +--query_vertical show status like 'Slave_heartbeat_period'; + +reset slave; + +# +# A warning if period greater than slave_net_timeout +# +set @@global.slave_net_timeout= 5; +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 5.001; +--query_vertical show status like 'Slave_heartbeat_period'; + +reset slave; + +# +# A warning if slave_net_timeout is set to less than the current HB period +# +set @@global.slave_net_timeout= 5; +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4; +--query_vertical show status like 'Slave_heartbeat_period'; +set @@global.slave_net_timeout= 3 /* must be a warning */; + +reset slave; + + +### +### checking no rotation +### + +connection master; +--disable_warnings +drop table if exists t1; +--enable_warnings +# +# Even though master_heartbeat_period= 0.5 is 20 times less than +# @@global.slave_net_timeout= 10 in some circumstances master will +# not be able to send any heartbeat during the slave's net timeout +# and slave's relay log will rotate. +# The probability for such a scenario is pretty small so the following +# part is almost deterministic. +# + +connection slave; +set @@global.slave_net_timeout= 10; +--replace_result $MASTER_MYPORT MASTER_PORT +# no error this time but rather a warning +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.5; +--query_vertical show status like 'Slave_heartbeat_period'; + +start slave; + +connection master; +create table t1 (f1 int); + +#connection slave; +sync_slave_with_master; +source include/show_slave_status.inc; + +# there is an explicit sleep lasting longer than slave_net_timeout +# to ensure that nothing will come to slave from master for that period. +# That would cause reconnecting and relaylog rotation w/o the fix i.e +# without a heartbeat received. + +real_sleep 15; + +# check (compare with the previous show's results) that no rotation happened +source include/show_slave_status.inc; + +### +### SHOW STATUS like 'Slave_heartbeat_period' and 'Slave_received_heartbeats' +### + +--query_vertical show status like 'Slave_heartbeat_period'; + +# +# proof that there has been received at least one heartbeat; +# The exact number of received heartbeat is an indeterministic value +# and therefore it's not recorded into results. +# + +let $slave_wait_param_counter= 300; +let $slave_value= query_get_value("SHOW STATUS like 'Slave_received_heartbeats'", Value, 1); +# Checking the fact that at least one heartbeat is received +while (`select $slave_value = 0`) +{ + dec $slave_wait_param_counter; + if (!$slave_wait_param_counter) + { + --echo ERROR: failed while waiting for slave parameter $slave_param: $slave_param_value + query_vertical show slave status; + SHOW STATUS like 'Slave_received_heartbeats'; + exit; + } + sleep 0.1; + let $slave_value= query_get_value("SHOW STATUS like 'Slave_received_heartbeats'", Value, 1); +} +--echo A heartbeat has been received by the slave +# cleanup + +connection master; +drop table t1; + +#connection slave; +sync_slave_with_master; + + +--echo End of tests From c676cebbea734691b41bf7e8edcbe61e74a53f62 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Tue, 29 Sep 2009 14:37:52 +0300 Subject: [PATCH 025/274] WL#342 heartbeat Improving an error report generating. --- sql/slave.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sql/slave.cc b/sql/slave.cc index 4a161a345eb..bbdfb8e633f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1233,11 +1233,10 @@ when it try to get the value of TIME_ZONE global variable from master."; if (mysql_real_query(mysql, query, strlen(query)) && !check_io_slave_killed(mi->io_thd, mi, NULL)) { - errmsg= "The slave I/O thread stops because querying master with '%s' " - "failed; error: '%s' "; + errmsg= "The slave I/O thread stops because SET @master_heartbeat_period " + "on master failed."; err_code= ER_SLAVE_FATAL_ERROR; - sprintf(err_buff, "%s Error: %s", errmsg, - query, mysql_error(mysql)); + sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql)); mysql_free_result(mysql_store_result(mysql)); goto err; } From 569ca8590c76e75a06d3ec2f320b7ea2b6960072 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Tue, 29 Sep 2009 14:38:32 +0100 Subject: [PATCH 026/274] BUG#44663 Unused replication options prevent server from starting. NOTE: Backporting the patch to next-mr. The use of option log_slave_updates without log_bin was preventing the server from starting. To fix the problem, we replaced the error message and the exit call by a warning message. --- sql/mysqld.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9b70096eb73..a57ee04081f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3819,9 +3819,8 @@ with --log-bin instead."); } if (opt_log_slave_updates && !opt_bin_log) { - sql_print_error("You need to use --log-bin to make " + sql_print_warning("You need to use --log-bin to make " "--log-slave-updates work."); - unireg_abort(1); } if (!opt_bin_log) { @@ -3851,11 +3850,17 @@ with --log-bin instead."); #ifdef HAVE_REPLICATION if (opt_log_slave_updates && replicate_same_server_id) { - sql_print_error("\ -using --replicate-same-server-id in conjunction with \ + if (opt_bin_log) + { + sql_print_error("using --replicate-same-server-id in conjunction with \ --log-slave-updates is impossible, it would lead to infinite loops in this \ server."); - unireg_abort(1); + unireg_abort(1); + } + else + sql_print_warning("using --replicate-same-server-id in conjunction with \ +--log-slave-updates would lead to infinite loops in this server. However this \ +will be ignored as the --log-bin option is not defined."); } #endif From b7f887652b22d49574860d6948e67f0ea7a83294 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Tue, 29 Sep 2009 14:55:36 +0100 Subject: [PATCH 027/274] WL#4828 and BUG#45747 NOTE: Backporting the patch to next-mr. WL#4828 Augment DBUG_ENTER/DBUG_EXIT to crash MySQL in different functions ------- The assessment of the replication code in the presence of faults is extremely import to increase reliability. In particular, one needs to know if servers will either correctly recovery or print out appropriate error messages thus avoiding unexpected problems in a production environment. In order to accomplish this, the current patch refactories the debug macros already provided in the source code and introduces three new macros that allows to inject faults, specifically crashes, while entering or exiting a function or method. For instance, to crash a server while returning from the init_slave function (see module sql/slave.cc), one needs to do what follows: 1 - Modify the source replacing DBUG_RETURN by DBUG_CRASH_RETURN; DBUG_CRASH_RETURN(0); 2 - Use the debug variable to activate dbug instructions: SET SESSION debug="+d,init_slave_crash_return"; The new macros are briefly described below: DBUG_CRASH_ENTER (function) is equivalent to DBUG_ENTER which registers the beginning of a function but in addition to it allows for crashing the server while entering the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_enter". DBUG_CRASH_RETURN (value) is equivalent to DBUG_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. DBUG_CRASH_VOID_RETURN (value) is equivalent to DBUG_VOID_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. To inject other faults, for instance, wrong return values, one should rely on the macros already available. The current patch also removes a set of macros that were either not being used or were redundant as other macros could be used to provide the same feature. In the future, we also consider dynamic instrumentation of the code. BUG#45747 DBUG_CRASH_* is not setting the strict option --------- When combining DBUG_CRASH_* with "--debug=d:t:i:A,file" the server crashes due to a call to the abort function in the DBUG_CRASH_* macro althought the appropriate keyword has not been set. --- dbug/dbug.c | 28 +++++++++++++ include/my_dbug.h | 19 +++++++++ sql/mysql_priv.h | 94 -------------------------------------------- sql/sql_class.cc | 3 -- sql/sql_class.h | 3 -- sql/sql_partition.cc | 4 ++ 6 files changed, 51 insertions(+), 100 deletions(-) diff --git a/dbug/dbug.c b/dbug/dbug.c index baf080f5e27..1ea160852eb 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -1662,6 +1662,27 @@ BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword) InList(cs->stack->processes, cs->process)); } +/* + * FUNCTION + * + * _db_keywords_ test keyword formed by a set of strings for member + * of keyword list + * + * DESCRIPTION + * + * This function is similar to _db_keyword but receives a set of strings to + * be concatenated in order to make the keyword to be compared. + */ + +BOOLEAN _db_keywords_(const char *function, const char *type) +{ + char dest[_DBUG_MAX_FUNC_NAME_ + 1]; + + strxnmov(dest, _DBUG_MAX_FUNC_NAME_, function, type, NULL); + + return _db_strict_keyword_(dest); +} + /* * FUNCTION * @@ -2281,6 +2302,13 @@ void _db_unlock_file_() pthread_mutex_unlock(&THR_LOCK_dbug); } +const char* _db_get_func_(void) +{ + CODE_STATE *cs= 0; + get_code_state_or_return NULL; + return cs->func; +} + /* * Here we need the definitions of the clock routine. Add your * own for whatever system that you have. diff --git a/include/my_dbug.h b/include/my_dbug.h index a77e439b5db..7df080bee72 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -22,6 +22,7 @@ extern "C" { #if !defined(DBUG_OFF) && !defined(_lint) struct _db_code_state_; extern int _db_keyword_(struct _db_code_state_ *cs, const char *keyword); +extern int _db_keywords_(const char *, const char *); extern int _db_strict_keyword_(const char *keyword); extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len); extern int _db_explain_init_(char *buf, size_t len); @@ -46,6 +47,7 @@ extern void _db_end_(void); extern void _db_lock_file_(void); extern void _db_unlock_file_(void); extern FILE *_db_fp_(void); +extern const char* _db_get_func_(void); #define DBUG_ENTER(a) const char *_db_func_, *_db_file_; uint _db_level_; \ char **_db_framep_; \ @@ -81,6 +83,20 @@ extern FILE *_db_fp_(void); #define DBUG_EXPLAIN(buf,len) _db_explain_(0, (buf),(len)) #define DBUG_EXPLAIN_INITIAL(buf,len) _db_explain_init_((buf),(len)) #define IF_DBUG(A) A +#define _DBUG_MAX_FUNC_NAME_ 255 +#define DBUG_CHECK_CRASH(func, op) \ + do { \ + if (_db_keywords_((func), (op))) \ + { abort(); } \ + } while (0) +#define DBUG_CRASH_ENTER(func) \ + DBUG_ENTER(func); DBUG_CHECK_CRASH(func, "_crash_enter") +#define DBUG_CRASH_RETURN(val) \ + do {DBUG_CHECK_CRASH(_db_get_func_(), "_crash_return"); \ + DBUG_RETURN(val);} while(0) +#define DBUG_CRASH_VOID_RETURN \ + do {DBUG_CHECK_CRASH (_db_get_func_(), "_crash_return"); \ + DBUG_VOID_RETURN;} while(0) #else /* No debugger */ #define DBUG_ENTER(a1) @@ -108,6 +124,9 @@ extern FILE *_db_fp_(void); #define DBUG_EXPLAIN(buf,len) #define DBUG_EXPLAIN_INITIAL(buf,len) #define IF_DBUG(A) +#define DBUG_CRASH_ENTER(func) +#define DBUG_CRASH_RETURN(val) do { return(val); } while(0) +#define DBUG_CRASH_VOID_RETURN do { return; } while(0) #endif #ifdef __cplusplus } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 381a0313add..52cfa7934c3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -938,100 +938,6 @@ struct Query_cache_query_flags #define query_cache_is_cacheable_query(L) 0 #endif /*HAVE_QUERY_CACHE*/ -/* - Error injector Macros to enable easy testing of recovery after failures - in various error cases. -*/ -#ifndef ERROR_INJECT_SUPPORT - -#define ERROR_INJECT(x) 0 -#define ERROR_INJECT_ACTION(x,action) 0 -#define ERROR_INJECT_CRASH(x) 0 -#define ERROR_INJECT_VALUE(x) 0 -#define ERROR_INJECT_VALUE_ACTION(x,action) 0 -#define ERROR_INJECT_VALUE_CRASH(x) 0 -#define SET_ERROR_INJECT_VALUE(x) - -#else - -inline bool check_and_unset_keyword(const char *dbug_str) -{ - const char *extra_str= "-d,"; - char total_str[200]; - if (_db_strict_keyword_ (dbug_str)) - { - strxmov(total_str, extra_str, dbug_str, NullS); - DBUG_SET(total_str); - return 1; - } - return 0; -} - - -inline bool -check_and_unset_inject_value(int value) -{ - THD *thd= current_thd; - if (thd->error_inject_value == (uint)value) - { - thd->error_inject_value= 0; - return 1; - } - return 0; -} - -/* - ERROR INJECT MODULE: - -------------------- - These macros are used to insert macros from the application code. - The event that activates those error injections can be activated - from SQL by using: - SET SESSION dbug=+d,code; - - After the error has been injected, the macros will automatically - remove the debug code, thus similar to using: - SET SESSION dbug=-d,code - from SQL. - - ERROR_INJECT_CRASH will inject a crash of the MySQL Server if code - is set when macro is called. ERROR_INJECT_CRASH can be used in - if-statements, it will always return FALSE unless of course it - crashes in which case it doesn't return at all. - - ERROR_INJECT_ACTION will inject the action specified in the action - parameter of the macro, before performing the action the code will - be removed such that no more events occur. ERROR_INJECT_ACTION - can also be used in if-statements and always returns FALSE. - ERROR_INJECT can be used in a normal if-statement, where the action - part is performed in the if-block. The macro returns TRUE if the - error was activated and otherwise returns FALSE. If activated the - code is removed. - - Sometimes it is necessary to perform error inject actions as a serie - of events. In this case one can use one variable on the THD object. - Thus one sets this value by using e.g. SET_ERROR_INJECT_VALUE(100). - Then one can later test for it by using ERROR_INJECT_CRASH_VALUE, - ERROR_INJECT_ACTION_VALUE and ERROR_INJECT_VALUE. This have the same - behaviour as the above described macros except that they use the - error inject value instead of a code used by DBUG macros. -*/ -#define SET_ERROR_INJECT_VALUE(x) \ - current_thd->error_inject_value= (x) -#define ERROR_INJECT_CRASH(code) \ - DBUG_EVALUATE_IF(code, (abort(), 0), 0) -#define ERROR_INJECT_ACTION(code, action) \ - (check_and_unset_keyword(code) ? ((action), 0) : 0) -#define ERROR_INJECT(code) \ - check_and_unset_keyword(code) -#define ERROR_INJECT_VALUE(value) \ - check_and_unset_inject_value(value) -#define ERROR_INJECT_VALUE_ACTION(value,action) \ - (check_and_unset_inject_value(value) ? (action) : 0) -#define ERROR_INJECT_VALUE_CRASH(value) \ - ERROR_INJECT_VALUE_ACTION(value, (abort(), 0)) - -#endif - void write_bin_log(THD *thd, bool clear_error, char const *query, ulong query_length); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 3f568566c89..6c2133ae6c8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -586,9 +586,6 @@ THD::THD() limit_found_rows= 0; row_count_func= -1; statement_id_counter= 0UL; -#ifdef ERROR_INJECT_SUPPORT - error_inject_value= 0UL; -#endif // Must be reset to handle error with THD's created for init of mysqld lex->current_select= 0; start_time=(time_t) 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index 49f9bc3fd5e..47b51559ed1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1720,9 +1720,6 @@ public: query_id_t query_id, warn_id; ulong col_access; -#ifdef ERROR_INJECT_SUPPORT - ulong error_inject_value; -#endif /* Statement id is thread-wide. This counter is used to generate ids */ ulong statement_id_counter; ulong rand_saved_seed1, rand_saved_seed2; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 08ff2daacb9..a4c0f02e480 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -40,6 +40,10 @@ #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" + +#define ERROR_INJECT_CRASH(code) \ + DBUG_EVALUATE_IF(code, (abort(), 0), 0) + /* Partition related functions declarations and some static constants; */ From cc9e25af54ac0a00cfe9930253a0e6de70f0c668 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Tue, 29 Sep 2009 15:04:21 +0100 Subject: [PATCH 028/274] BUG#38173 Field doesn't have a default value with row-based replication NOTE: Backporting the patch to next-mr. The reason of the bug was incompatibile with the master side behaviour. INSERT query on the master is allowed to insert into a table without specifying values of DEFAULT-less fields if sql_mode is not strict. Fixed with checking sql_mode by the sql thread to decide how to react. Non-strict sql_mode should allow Write_rows event to complete. todo: warnings can be shown via show slave status, still this is a separate rather general issue how to show warnings for the slave threads. --- .../extra/rpl_tests/rpl_extraSlave_Col.test | 35 +++++++++---- .../extra/rpl_tests/rpl_row_tabledefs.test | 15 +++--- .../suite/rpl/r/rpl_extraCol_innodb.result | 52 ++++--------------- .../suite/rpl/r/rpl_extraCol_myisam.result | 52 ++++--------------- .../rpl/r/rpl_row_tabledefs_2myisam.result | 44 ++-------------- .../rpl/r/rpl_row_tabledefs_3innodb.result | 44 ++-------------- sql/log_event.cc | 5 +- sql/rpl_record.cc | 34 ++++++++---- sql/rpl_record.h | 3 +- 9 files changed, 88 insertions(+), 196 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index a7b02065144..1eaefa661f9 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -407,13 +407,18 @@ sync_slave_with_master; ########################################### # Bug#22234, Bug#23907 Extra Slave Col is not # erroring on extra col with no default values. -######################################################## +############################################################### +# Error reaction is up to sql_mode of the slave sql (bug#38173) #--echo *** Create t9 on slave *** STOP SLAVE; RESET SLAVE; eval CREATE TABLE t9 (a INT KEY, b BLOB, c CHAR(5), d TIMESTAMP, - e INT NOT NULL) ENGINE=$engine_type; + e INT NOT NULL, + f text not null, + g text, + h blob not null, + i blob) ENGINE=$engine_type; --echo *** Create t9 on Master *** connection master; @@ -431,13 +436,25 @@ set @b1 = 'b1b1b1b1'; set @b1 = concat(@b1,@b1); INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA'); -connection slave; ---source include/wait_for_slave_sql_to_stop.inc ---replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 # ---query_vertical SHOW SLAVE STATUS -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; +# the test would stop slave if @@sql_mode for the sql thread +# was set to strict. Otherwise, as with this tests setup, +# the implicit defaults will be inserted into fields even though +# they are declared without DEFAULT clause. + +sync_slave_with_master; +select * from t9; + +# todo: fix Bug #43992 slave sql thread can't tune own sql_mode ... +# and add/restore waiting for stop test + +#--source include/wait_for_slave_sql_to_stop.inc +#--replace_result $MASTER_MYPORT MASTER_PORT +#--replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 # +#--query_vertical SHOW SLAVE STATUS +#SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +#START SLAVE; + + #--echo *** Drop t9 *** #connection master; diff --git a/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test b/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test index 3b03caee35c..083088f12ff 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test +++ b/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test @@ -111,21 +111,18 @@ SELECT a,b,x FROM t1_int ORDER BY a; SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit ORDER BY a; SELECT a,b,x FROM t1_char ORDER BY a; -# Each of these inserts should generate an error and stop the slave - connection master; INSERT INTO t9 VALUES (2); sync_slave_with_master; # Now slave is guaranteed to be running connection master; INSERT INTO t1_nodef VALUES (1,2); -connection slave; ---source include/wait_for_slave_sql_to_stop.inc ---replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 4 # 7 # 8 # 9 # 20 22 # 23 # 33 # 35 36 38 ---query_vertical SHOW SLAVE STATUS -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; + +# Last insert on wider slave table succeeds while slave sql sql_mode permits. +# The previous version of the above test expected slave sql to stop. +# bug#38173 relaxed conditions to stop only with the strict mode. +sync_slave_with_master; +select count(*) from t1_nodef; # # Replicating to tables with fewer columns at the end works as of WL#3228 diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result index e2ec78e7adc..63154383e8c 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result @@ -404,7 +404,11 @@ STOP SLAVE; RESET SLAVE; CREATE TABLE t9 (a INT KEY, b BLOB, c CHAR(5), d TIMESTAMP, -e INT NOT NULL) ENGINE='InnoDB'; +e INT NOT NULL, +f text not null, +g text, +h blob not null, +i blob) ENGINE='InnoDB'; *** Create t9 on Master *** CREATE TABLE t9 (a INT PRIMARY KEY, b BLOB, c CHAR(5) ) ENGINE='InnoDB'; @@ -415,47 +419,11 @@ START SLAVE; set @b1 = 'b1b1b1b1'; set @b1 = concat(@b1,@b1); INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA'); -SHOW SLAVE STATUS; -Slave_IO_State # -Master_Host 127.0.0.1 -Master_User root -Master_Port # -Connect_Retry 1 -Master_Log_File master-bin.000001 -Read_Master_Log_Pos # -Relay_Log_File # -Relay_Log_Pos # -Relay_Master_Log_File master-bin.000001 -Slave_IO_Running Yes -Slave_SQL_Running No -Replicate_Do_DB -Replicate_Ignore_DB -Replicate_Do_Table -Replicate_Ignore_Table # -Replicate_Wild_Do_Table -Replicate_Wild_Ignore_Table -Last_Errno 1364 -Last_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 330 -Skip_Counter 0 -Exec_Master_Log_Pos # -Relay_Log_Space # -Until_Condition None -Until_Log_File -Until_Log_Pos 0 -Master_SSL_Allowed No -Master_SSL_CA_File -Master_SSL_CA_Path -Master_SSL_Cert -Master_SSL_Cipher -Master_SSL_Key -Seconds_Behind_Master # -Master_SSL_Verify_Server_Cert No -Last_IO_Errno # -Last_IO_Error # -Last_SQL_Errno 1364 -Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 330 -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; +select * from t9; +a b c d e f g h i +1 b1b1b1b1b1b1b1b1 Kyle 0000-00-00 00:00:00 0 NULL NULL +2 b1b1b1b1b1b1b1b1 JOE 0000-00-00 00:00:00 0 NULL NULL +3 b1b1b1b1b1b1b1b1 QA 0000-00-00 00:00:00 0 NULL NULL *** Create t10 on slave *** STOP SLAVE; RESET SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result index ed5b4eac27d..d80ac5eea2c 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result @@ -404,7 +404,11 @@ STOP SLAVE; RESET SLAVE; CREATE TABLE t9 (a INT KEY, b BLOB, c CHAR(5), d TIMESTAMP, -e INT NOT NULL) ENGINE='MyISAM'; +e INT NOT NULL, +f text not null, +g text, +h blob not null, +i blob) ENGINE='MyISAM'; *** Create t9 on Master *** CREATE TABLE t9 (a INT PRIMARY KEY, b BLOB, c CHAR(5) ) ENGINE='MyISAM'; @@ -415,47 +419,11 @@ START SLAVE; set @b1 = 'b1b1b1b1'; set @b1 = concat(@b1,@b1); INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA'); -SHOW SLAVE STATUS; -Slave_IO_State # -Master_Host 127.0.0.1 -Master_User root -Master_Port # -Connect_Retry 1 -Master_Log_File master-bin.000001 -Read_Master_Log_Pos # -Relay_Log_File # -Relay_Log_Pos # -Relay_Master_Log_File master-bin.000001 -Slave_IO_Running Yes -Slave_SQL_Running No -Replicate_Do_DB -Replicate_Ignore_DB -Replicate_Do_Table -Replicate_Ignore_Table # -Replicate_Wild_Do_Table -Replicate_Wild_Ignore_Table -Last_Errno 1364 -Last_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 330 -Skip_Counter 0 -Exec_Master_Log_Pos # -Relay_Log_Space # -Until_Condition None -Until_Log_File -Until_Log_Pos 0 -Master_SSL_Allowed No -Master_SSL_CA_File -Master_SSL_CA_Path -Master_SSL_Cert -Master_SSL_Cipher -Master_SSL_Key -Seconds_Behind_Master # -Master_SSL_Verify_Server_Cert No -Last_IO_Errno # -Last_IO_Error # -Last_SQL_Errno 1364 -Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 330 -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; +select * from t9; +a b c d e f g h i +1 b1b1b1b1b1b1b1b1 Kyle 0000-00-00 00:00:00 0 NULL NULL +2 b1b1b1b1b1b1b1b1 JOE 0000-00-00 00:00:00 0 NULL NULL +3 b1b1b1b1b1b1b1b1 QA 0000-00-00 00:00:00 0 NULL NULL *** Create t10 on slave *** STOP SLAVE; RESET SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result index a6a2181cd2a..bb9865ab2d1 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result @@ -105,47 +105,9 @@ a b x 2 10 Foo is a bar INSERT INTO t9 VALUES (2); INSERT INTO t1_nodef VALUES (1,2); -SHOW SLAVE STATUS; -Slave_IO_State # -Master_Host 127.0.0.1 -Master_User root -Master_Port # -Connect_Retry 1 -Master_Log_File master-bin.000001 -Read_Master_Log_Pos # -Relay_Log_File # -Relay_Log_Pos # -Relay_Master_Log_File master-bin.000001 -Slave_IO_Running Yes -Slave_SQL_Running No -Replicate_Do_DB -Replicate_Ignore_DB -Replicate_Do_Table -Replicate_Ignore_Table -Replicate_Wild_Do_Table -Replicate_Wild_Ignore_Table -Last_Errno 1364 -Last_Error -Skip_Counter 0 -Exec_Master_Log_Pos # -Relay_Log_Space # -Until_Condition None -Until_Log_File -Until_Log_Pos 0 -Master_SSL_Allowed No -Master_SSL_CA_File -Master_SSL_CA_Path -Master_SSL_Cert -Master_SSL_Cipher -Master_SSL_Key -Seconds_Behind_Master # -Master_SSL_Verify_Server_Cert No -Last_IO_Errno -Last_IO_Error -Last_SQL_Errno 1364 -Last_SQL_Error -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; +select count(*) from t1_nodef; +count(*) +1 INSERT INTO t9 VALUES (2); **** On Master **** INSERT INTO t2 VALUES (2,4); diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result index 02e8c074354..f606a28c2d9 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result @@ -105,47 +105,9 @@ a b x 2 10 Foo is a bar INSERT INTO t9 VALUES (2); INSERT INTO t1_nodef VALUES (1,2); -SHOW SLAVE STATUS; -Slave_IO_State # -Master_Host 127.0.0.1 -Master_User root -Master_Port # -Connect_Retry 1 -Master_Log_File master-bin.000001 -Read_Master_Log_Pos # -Relay_Log_File # -Relay_Log_Pos # -Relay_Master_Log_File master-bin.000001 -Slave_IO_Running Yes -Slave_SQL_Running No -Replicate_Do_DB -Replicate_Ignore_DB -Replicate_Do_Table -Replicate_Ignore_Table -Replicate_Wild_Do_Table -Replicate_Wild_Ignore_Table -Last_Errno 1364 -Last_Error -Skip_Counter 0 -Exec_Master_Log_Pos # -Relay_Log_Space # -Until_Condition None -Until_Log_File -Until_Log_Pos 0 -Master_SSL_Allowed No -Master_SSL_CA_File -Master_SSL_CA_Path -Master_SSL_Cert -Master_SSL_Cipher -Master_SSL_Key -Seconds_Behind_Master # -Master_SSL_Verify_Server_Cert No -Last_IO_Errno -Last_IO_Error -Last_SQL_Errno 1364 -Last_SQL_Error -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; +select count(*) from t1_nodef; +count(*) +1 INSERT INTO t9 VALUES (2); **** On Master **** INSERT INTO t2 VALUES (2,4); diff --git a/sql/log_event.cc b/sql/log_event.cc index fb6a5230fda..d595f00bffd 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8446,7 +8446,10 @@ Rows_log_event::write_row(const Relay_log_info *const rli, /* fill table->record[0] with default values */ if ((error= prepare_record(table, m_width, - TRUE /* check if columns have def. values */))) + table->file->ht->db_type != DB_TYPE_NDBCLUSTER, + (rli->sql_thd->variables.sql_mode & + (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES))))) DBUG_RETURN(error); /* unpack row into table->record[0] */ diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 14a80cbb4b6..f4768e2456a 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -305,13 +305,17 @@ unpack_row(Relay_log_info const *rli, @param table Table whose record[0] buffer is prepared. @param skip Number of columns for which default/nullable check should be skipped. - @param check Indicates if errors should be raised when checking - default/nullable field properties. + @param check Specifies if lack of default error needs checking. + @param abort_on_warning + Controls how to react on lack of a field's default. + The parameter mimics the master side one for + @c check_that_all_fields_are_given_values. @returns 0 on success or a handler level error code */ int prepare_record(TABLE *const table, - const uint skip, const bool check) + const uint skip, const bool check, + const bool abort_on_warning) { DBUG_ENTER("prepare_record"); @@ -326,17 +330,27 @@ int prepare_record(TABLE *const table, if (skip >= table->s->fields || !check) DBUG_RETURN(0); - /* Checking if exists default/nullable fields in the default values. */ - - for (Field **field_ptr= table->field+skip ; *field_ptr ; ++field_ptr) + /* + For fields the extra fields on the slave, we check if they have a default. + The check follows the same rules as the INSERT query without specifying an + explicit value for a field not having the explicit default + (@c check_that_all_fields_are_given_values()). + */ + for (Field **field_ptr= table->field+skip; *field_ptr; ++field_ptr) { uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG; Field *const f= *field_ptr; - - if (((f->flags & mask) == mask)) + if ((f->flags & NO_DEFAULT_VALUE_FLAG) && + (f->real_type() != MYSQL_TYPE_ENUM)) { - my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), f->field_name); - error = HA_ERR_ROWS_EVENT_APPLY; + push_warning_printf(current_thd, abort_on_warning? + MYSQL_ERROR::WARN_LEVEL_ERROR : + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_FIELD, + ER(ER_NO_DEFAULT_FOR_FIELD), + f->field_name); + if (abort_on_warning) + error = HA_ERR_ROWS_EVENT_APPLY; } } diff --git a/sql/rpl_record.h b/sql/rpl_record.h index f9e64f0ab1d..ab2bcd382ca 100644 --- a/sql/rpl_record.h +++ b/sql/rpl_record.h @@ -30,7 +30,8 @@ int unpack_row(Relay_log_info const *rli, uchar const **const row_end, ulong *const master_reclength); // Fill table's record[0] with default values. -int prepare_record(TABLE *const, const uint =0, const bool =FALSE); +int prepare_record(TABLE *const table, const uint skip, const bool check, + const bool abort_on_warning= FALSE); #endif #endif From 01cdba58ba758e468d01770e87bca7f22790a184 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 29 Sep 2009 15:09:01 +0100 Subject: [PATCH 029/274] BUG#23300: Slow query log on slave does not log slow replicated statements NOTE: this is the backport to next-mr. When using replication, the slave will not log any slow query logs queries replicated from the master, even if the option "--log-slow-slave-statements" is set and these take more than "log_query_time" to execute. In order to log slow queries in replicated thread one needs to set the --log-slow-slave-statements, so that the SQL thread is initialized with the correct switch. Although setting this flag correctly configures the slave thread option to log slow queries, there is an issue with the condition that is used to check whether to log the slow query or not. When replaying binlog events the statement contains the SET TIMESTAMP clause which will force the slow logging condition check to fail. Consequently, the slow query logging will not take place. This patch addresses this issue by removing the second condition from the log_slow_statements as it prevents slow queries to be binlogged and seems to be deprecated. --- .../suite/rpl/r/rpl_slow_query_log.result | 47 +++++ .../suite/rpl/t/rpl_slow_query_log-slave.opt | 1 + .../suite/rpl/t/rpl_slow_query_log.test | 187 ++++++++++++++++++ sql/log.cc | 1 + sql/sql_parse.cc | 4 +- 5 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_slow_query_log.result create mode 100644 mysql-test/suite/rpl/t/rpl_slow_query_log-slave.opt create mode 100644 mysql-test/suite/rpl/t/rpl_slow_query_log.test diff --git a/mysql-test/suite/rpl/r/rpl_slow_query_log.result b/mysql-test/suite/rpl/r/rpl_slow_query_log.result new file mode 100644 index 00000000000..ced357b21e9 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_slow_query_log.result @@ -0,0 +1,47 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +include/stop_slave.inc +SET @old_log_output= @@log_output; +SET GLOBAL log_output= 'TABLE'; +SET @old_long_query_time= @@long_query_time; +SET GLOBAL long_query_time= 2; +TRUNCATE mysql.slow_log; +include/start_slave.inc +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 values(1, 1); +INSERT INTO t1 values(1, sleep(3)); +TRUNCATE mysql.slow_log; +SELECT 1, sleep(3); +1 sleep(3) +1 0 +SELECT 1; +1 +1 +TRUNCATE mysql.slow_log; +SET TIMESTAMP= 1; +SELECT 2, sleep(3); +2 sleep(3) +2 0 +SELECT 2; +2 +2 +TRUNCATE mysql.slow_log; +SET @old_slow_query_log= @@slow_query_log; +SET GLOBAL slow_query_log= 'OFF'; +SELECT 3, sleep(3); +3 sleep(3) +3 0 +SELECT 3; +3 +3 +TRUNCATE mysql.slow_log; +SET GLOBAL slow_query_log= @old_slow_query_log; +DROP TABLE t1; +include/stop_slave.inc +SET GLOBAL long_query_time= @old_long_query_time; +SET GLOBAL log_output= @old_log_output; +include/start_slave.inc diff --git a/mysql-test/suite/rpl/t/rpl_slow_query_log-slave.opt b/mysql-test/suite/rpl/t/rpl_slow_query_log-slave.opt new file mode 100644 index 00000000000..a27d3a0f5a7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slow_query_log-slave.opt @@ -0,0 +1 @@ +--force-restart --log-slow-slave-statements --log-slow-queries diff --git a/mysql-test/suite/rpl/t/rpl_slow_query_log.test b/mysql-test/suite/rpl/t/rpl_slow_query_log.test new file mode 100644 index 00000000000..1d5fcf950f2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slow_query_log.test @@ -0,0 +1,187 @@ +# +# BUG#23300: Slow query log on slave does not log slow replicated statements +# +# Description: +# The slave should log slow queries replicated from master when +# --log-slow-slave-statements is used. +# +# Test is implemented as follows: +# i) stop slave +# ii) On slave, set long_query_time to a small value. +# ii) start slave so that long_query_time variable is picked by sql thread +# iii) On master, do one short time query and one long time query, on slave +# and check that slow query is logged to slow query log but fast query +# is not. +# iv) On slave, check that slow queries go into the slow log and fast dont, +# when issued through a regular client connection +# v) On slave, check that slow queries go into the slow log and fast dont +# when we use SET TIMESTAMP= 1 on a regular client connection. +# vi) check that when setting slow_query_log= OFF in a connection 'extra2' +# prevents logging slow queries in a connection 'extra' +# +# OBS: +# This test only runs for statement and mixed binlogging firmat because on +# row format slow queries do not get slow query logged. + +source include/master-slave.inc; +source include/have_binlog_format_mixed_or_statement.inc; + + +# Prepare slave for different long_query_time we need to stop the slave +# and restart it as long_query_time variable is dynamic and, after +# setting it, it only takes effect on new connections. +# +# Reference: +# http://dev.mysql.com/doc/refman/6.0/en/set-option.html +connection slave; + +source include/stop_slave.inc; + +SET @old_log_output= @@log_output; +SET GLOBAL log_output= 'TABLE'; +SET @old_long_query_time= @@long_query_time; +SET GLOBAL long_query_time= 2; +TRUNCATE mysql.slow_log; + +source include/start_slave.inc; + +connection master; +CREATE TABLE t1 (a int, b int); + +# test: +# check that slave logs the slow query to the slow log, but not the fast one. + +let $slow_query= INSERT INTO t1 values(1, sleep(3)); +let $fast_query= INSERT INTO t1 values(1, 1); + +eval $fast_query; +eval $slow_query; +sync_slave_with_master; + +let $found_fast_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$fast_query'`; +let $found_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($found_fast_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Fast query FOUND in slow query log. Bailing out!"; +} + +if (!$found_slow_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Slow query NOT FOUND in slow query log. Bailing out!"; +} +TRUNCATE mysql.slow_log; + +# regular checks for slow query log (using a new connection - 'extra' - to slave) + +# test: +# when using direct connections to the slave, check that slow query is logged +# but not the fast one. + +connect(extra,127.0.0.1,root,,test,$SLAVE_MYPORT); +connection extra; + +let $fast_query= SELECT 1; +let $slow_query= SELECT 1, sleep(3); + +eval $slow_query; +eval $fast_query; + +let $found_fast_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$fast_query'`; +let $found_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($found_fast_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Fast query FOUND in slow query log. Bailing out!"; +} + +if (!$found_slow_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Slow query NOT FOUND in slow query log. Bailing out!"; +} +TRUNCATE mysql.slow_log; + +# test: +# when using direct connections to the slave, check that when setting timestamp to 1 the +# slow query is logged but the fast one is not. + +let $fast_query= SELECT 2; +let $slow_query= SELECT 2, sleep(3); + +SET TIMESTAMP= 1; +eval $slow_query; +eval $fast_query; + +let $found_fast_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$fast_query'`; +let $found_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($found_fast_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Fast query FOUND in slow query log. Bailing out!"; +} + +if (!$found_slow_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Slow query NOT FOUND in slow query log. Bailing out!"; +} +TRUNCATE mysql.slow_log; + +# test: +# check that when setting the slow_query_log= OFF on connection 'extra2' +# prevents connection 'extra' from logging to slow query log. + +let $fast_query= SELECT 3; +let $slow_query= SELECT 3, sleep(3); + +connect(extra2,127.0.0.1,root,,test,$SLAVE_MYPORT); +connection extra2; + +SET @old_slow_query_log= @@slow_query_log; +SET GLOBAL slow_query_log= 'OFF'; + +connection extra; + +eval $slow_query; +eval $fast_query; + +let $found_fast_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$fast_query'`; +let $found_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($found_fast_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Fast query FOUND in slow query log when slow_query_log= OFF. Bailing out!"; +} + +if ($found_slow_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Slow query FOUND in slow query log when slow_query_log= OFF. Bailing out!"; +} +TRUNCATE mysql.slow_log; + +# clean up: drop tables, reset the variables back to the previous value, +# disconnect extra connections +connection extra2; + +SET GLOBAL slow_query_log= @old_slow_query_log; + +connection master; +DROP TABLE t1; +sync_slave_with_master; + +source include/stop_slave.inc; + +SET GLOBAL long_query_time= @old_long_query_time; +SET GLOBAL log_output= @old_log_output; + +source include/start_slave.inc; + +disconnect extra; +disconnect extra2; diff --git a/sql/log.cc b/sql/log.cc index 1af2f3a4ddc..5c25d30bad0 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -961,6 +961,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, uint user_host_len= 0; ulonglong query_utime, lock_utime; + DBUG_ASSERT(thd->enable_slow_log); /* Print the message to the buffer if we have slow log enabled */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 513b9230c37..d0897646cec 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1615,9 +1615,9 @@ void log_slow_statement(THD *thd) /* Do not log administrative statements unless the appropriate option is - set; do not log into slow log if reading from backup. + set. */ - if (thd->enable_slow_log && !thd->user_time) + if (thd->enable_slow_log) { ulonglong end_utime_of_query= thd->current_utime(); thd_proc_info(thd, "logging slow query"); From b43d30e43a935ec53faea22fb7614550218ad42f Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 29 Sep 2009 15:09:46 +0100 Subject: [PATCH 030/274] BUG#28796: CHANGE MASTER TO MASTER_HOST="" leads to invalid master.info NOTE: this is the backport to next-mr. This patch addresses the bug reported by checking wether host argument is an empty string or not. If empty, an error is reported to the client, otherwise continue normally. This commit is based on the originally proposed patch and adds a test case as requested during review as well as refines comments, and makes test case result file less verbose (compared to previous patch). --- .../suite/rpl/r/rpl_empty_master_host.result | 16 ++++++ .../suite/rpl/t/rpl_empty_master_host.test | 51 +++++++++++++++++++ sql/sql_repl.cc | 13 +++++ 3 files changed, 80 insertions(+) create mode 100644 mysql-test/suite/rpl/r/rpl_empty_master_host.result create mode 100644 mysql-test/suite/rpl/t/rpl_empty_master_host.test diff --git a/mysql-test/suite/rpl/r/rpl_empty_master_host.result b/mysql-test/suite/rpl/r/rpl_empty_master_host.result new file mode 100644 index 00000000000..46ef32d415b --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_empty_master_host.result @@ -0,0 +1,16 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +STOP SLAVE; +Master_Host = '127.0.0.1' (expected '127.0.0.1') +CHANGE MASTER TO MASTER_HOST=""; +ERROR HY000: Incorrect arguments to MASTER_HOST +Master_Host = '127.0.0.1' (expected '127.0.0.1') +CHANGE MASTER TO MASTER_HOST="foo"; +Master_Host = 'foo' (expected 'foo') +CHANGE MASTER TO MASTER_HOST="127.0.0.1"; +Master_Host = '127.0.0.1' (expected '127.0.0.1') +START SLAVE; diff --git a/mysql-test/suite/rpl/t/rpl_empty_master_host.test b/mysql-test/suite/rpl/t/rpl_empty_master_host.test new file mode 100644 index 00000000000..7d245b1d5d5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_empty_master_host.test @@ -0,0 +1,51 @@ +# +# BUG +# --- +# BUG#28796: CHANGE MASTER TO MASTER_HOST="" leads to invalid master.info +# +# Description +# ----------- +# +# This test aims at: +# i) verifying that an error is thrown when setting MASTER_HOST='' +# ii) no error is thrown when setting non empty MASTER_HOST +# iii) replication works after setting a correct host name/ip +# +# Implementation is performed by feeding different values (according +# to i), ii) and iii) ) to CHANGE MASTER TO MASTER_HOST= x and checking +# along the way if error/no error is thrown and/or if replication starts +# working when expected. + +--source include/master-slave.inc + +connection slave; +STOP SLAVE; +--source include/wait_for_slave_to_stop.inc + +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master_Host = '$master_host' (expected '127.0.0.1') + +# attempt to change to an empty master host should +# result in error ER_WRONG_ARGUMENTS: "Incorrect arguments to ..." +error ER_WRONG_ARGUMENTS; +CHANGE MASTER TO MASTER_HOST=""; + +# show slave status still holds previous information +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master_Host = '$master_host' (expected '127.0.0.1') + +# changing master to other than empty master host succeeds +CHANGE MASTER TO MASTER_HOST="foo"; + +# show slave status should hold "foo" as master host +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master_Host = '$master_host' (expected 'foo') + +# changing back to localhost +CHANGE MASTER TO MASTER_HOST="127.0.0.1"; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master_Host = '$master_host' (expected '127.0.0.1') + +# start slave must succeed. +START SLAVE; +--source include/wait_for_slave_to_start.inc diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 4d9b7410b88..1cc21162022 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1150,6 +1150,19 @@ bool change_master(THD* thd, Master_info* mi) thd_proc_info(thd, "Changing master"); LEX_MASTER_INFO* lex_mi= &thd->lex->mi; + /* + We need to check if there is an empty master_host. Otherwise + change master succeeds, a master.info file is created containing + empty master_host string and when issuing: start slave; an error + is thrown stating that the server is not configured as slave. + (See BUG#28796). + */ + if(lex_mi->host && !*lex_mi->host) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "MASTER_HOST"); + unlock_slave_threads(mi); + DBUG_RETURN(TRUE); + } // TODO: see if needs re-write if (init_master_info(mi, master_info_file, relay_log_info_file, 0, thread_mask)) From b538536718389bcac283d875a7d92527d8ef57be Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 29 Sep 2009 15:10:37 +0100 Subject: [PATCH 031/274] Bug #30703 SHOW STATUS LIKE 'Slave_running' is not compatible with `SHOW SLAVE STATUS' NOTE: this is the backport to next-mr. SHOW SHOW STATUS LIKE 'Slave_running' command believes that if active_mi->slave_running != 0, then io thread is running normally. But it isn't so in fact. When some errors happen to make io thread try to reconnect master, then it will become transitional status (MYSQL_SLAVE_RUN_NOT_CONNECT == 1), which also doesn't equal 0. Yet, "SHOW SLAVE STATUS" believes that only if active_mi->slave_running == MYSQL_SLAVE_RUN_CONNECT, then io thread is running. So "SHOW SLAVE STATUS" can get the correct result. Fixed to make SHOW SHOW STATUS LIKE 'Slave_running' command have the same check condition with "SHOW SLAVE STATUS". It only believe that the io thread is running when active_mi->slave_running == MYSQL_SLAVE_RUN_CONNECT. --- mysql-test/include/test_fieldsize.inc | 2 +- sql/mysqld.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/include/test_fieldsize.inc b/mysql-test/include/test_fieldsize.inc index cbe63e26318..606bc63779d 100644 --- a/mysql-test/include/test_fieldsize.inc +++ b/mysql-test/include/test_fieldsize.inc @@ -22,7 +22,7 @@ eval $test_insert; connection slave; START SLAVE; -wait_for_slave_to_stop; +--source include/wait_for_slave_sql_to_stop.inc --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 # --query_vertical SHOW SLAVE STATUS diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9b70096eb73..9ae3db4762b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7043,7 +7043,8 @@ static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff) var->type= SHOW_MY_BOOL; pthread_mutex_lock(&LOCK_active_mi); var->value= buff; - *((my_bool *)buff)= (my_bool) (active_mi && active_mi->slave_running && + *((my_bool *)buff)= (my_bool) (active_mi && + active_mi->slave_running == MYSQL_SLAVE_RUN_CONNECT && active_mi->rli.slave_running); pthread_mutex_unlock(&LOCK_active_mi); return 0; From b79b335033fae28f891217a28d898c018b380f03 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 29 Sep 2009 15:12:07 +0100 Subject: [PATCH 032/274] BUG#40611: MySQL cannot make a binary log after sequential number beyond unsigned long. BUG#44779: binlog.binlog_max_extension may be causing failure on next test in PB NOTE1: this is the backport to next-mr. NOTE2: already includes patch for BUG#44779. Binlog file extensions would turn into negative numbers once the variable used to hold the value reached maximum for signed long. Consequently, incrementing value to the next (negative) number would lead to .000000 extension, causing the server to fail. This patch addresses this issue by not allowing negative extensions and by returning an error on find_uniq_filename, when the limit is reached. Additionally, warnings are printed to the error log when the limit is approaching. FLUSH LOGS will also report warnings to the user, if the extension number has reached the limit. The limit has been set to 0x7FFFFFFF as the maximum. mysql-test/suite/binlog/t/binlog_max_extension.test: Test case added that checks the maximum available number for binlog extensions. sql/log.cc: Changes to find_uniq_filename and test_if_number. sql/log.h: Added macros with values for MAX_LOG_UNIQUE_FN_EXT and LOG_WARN_UNIQUE_FN_EXT_LEFT, as suggested in review. --- .../binlog/r/binlog_max_extension.result | 8 ++ .../suite/binlog/t/binlog_max_extension.test | 92 +++++++++++++++++++ sql/log.cc | 75 ++++++++++++--- sql/log.h | 13 +++ 4 files changed, 174 insertions(+), 14 deletions(-) create mode 100644 mysql-test/suite/binlog/r/binlog_max_extension.result create mode 100644 mysql-test/suite/binlog/t/binlog_max_extension.test diff --git a/mysql-test/suite/binlog/r/binlog_max_extension.result b/mysql-test/suite/binlog/r/binlog_max_extension.result new file mode 100644 index 00000000000..af341db4536 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_max_extension.result @@ -0,0 +1,8 @@ +call mtr.add_suppression("Next log extension: 2147483647. Remaining log filename extensions: 0."); +call mtr.add_suppression("Log filename extension number exhausted:"); +call mtr.add_suppression("Can't generate a unique log-filename"); +RESET MASTER; +FLUSH LOGS; +Warnings: +Warning 1098 Can't generate a unique log-filename master-bin.(1-999) + diff --git a/mysql-test/suite/binlog/t/binlog_max_extension.test b/mysql-test/suite/binlog/t/binlog_max_extension.test new file mode 100644 index 00000000000..9f52d195e21 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_max_extension.test @@ -0,0 +1,92 @@ +# BUG#40611: MySQL cannot make a binary log after sequential number beyond +# unsigned long. +# +# Problem statement +# ================= +# +# Extension for log file names might be created with negative +# numbers (when counter used would wrap around), causing server +# failure when incrementing -00001 (reaching number 000000 +# extension). +# +# Test +# ==== +# This tests aims at testing the a patch that removes negatives +# numbers from log name extensions and checks that the server +# reports gracefully that the limit has been reached. +# +# It instruments index file to point to a log file close to +# the new maximum and calls flush logs to get warning. +# + +call mtr.add_suppression("Next log extension: 2147483647. Remaining log filename extensions: 0."); +call mtr.add_suppression("Log filename extension number exhausted:"); +call mtr.add_suppression("Can't generate a unique log-filename"); + + +-- source include/have_log_bin.inc +RESET MASTER; + +-- let $MYSQLD_DATADIR= `select @@datadir` + +############################################### +# check hitting maximum file name extension: +############################################### + +########## +# Prepare +########## + +# 1. Stop master server +-- write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF +-- shutdown_server 10 +-- source include/wait_until_disconnected.inc + +# 2. Prepare log and index file +-- copy_file $MYSQLD_DATADIR/master-bin.index $MYSQLD_DATADIR/master-bin.index.orig +-- copy_file $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.2147483646 +-- append_file $MYSQLD_DATADIR/master-bin.index +master-bin.2147483646 +EOF + +# 3. Restart the server +-- append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF +-- enable_reconnect +-- source include/wait_until_connected_again.inc + +########### +# Assertion +########### + +# assertion: should throw warning +FLUSH LOGS; + +############## +# Clean up +############## + +# 1. Stop the server +-- write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF +-- shutdown_server 10 +-- source include/wait_until_disconnected.inc + +# 2. Undo changes to index and log files +-- remove_file $MYSQLD_DATADIR/master-bin.index +-- copy_file $MYSQLD_DATADIR/master-bin.index.orig $MYSQLD_DATADIR/master-bin.index +-- remove_file $MYSQLD_DATADIR/master-bin.index.orig + +-- remove_file $MYSQLD_DATADIR/master-bin.2147483646 +-- remove_file $MYSQLD_DATADIR/master-bin.2147483647 + +# 3. Restart the server +-- append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF +-- enable_reconnect +-- source include/wait_until_connected_again.inc diff --git a/sql/log.cc b/sql/log.cc index 5c25d30bad0..19b26fcf5ab 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -53,7 +53,7 @@ MYSQL_BIN_LOG mysql_bin_log; ulong sync_binlog_counter= 0; static bool test_if_number(const char *str, - long *res, bool allow_wildcards); + ulong *res, bool allow_wildcards); static int binlog_init(void *p); static int binlog_close_connection(handlerton *hton, THD *thd); static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv); @@ -1835,22 +1835,27 @@ static void setup_windows_event_source() /** Find a unique filename for 'filename.#'. - Set '#' to a number as low as possible. + Set '#' to the number next to the maximum found in the most + recent log file extension. + + This function will return nonzero if: (i) the generated name + exceeds FN_REFLEN; (ii) if the number of extensions is exhausted; + or (iii) some other error happened while examining the filesystem. @return - nonzero if not possible to get unique filename + nonzero if not possible to get unique filename. */ static int find_uniq_filename(char *name) { - long number; uint i; - char buff[FN_REFLEN]; + char buff[FN_REFLEN], ext_buf[FN_REFLEN]; struct st_my_dir *dir_info; reg1 struct fileinfo *file_info; - ulong max_found=0; + ulong max_found= 0, next= 0, number= 0; size_t buf_length, length; char *start, *end; + int error= 0; DBUG_ENTER("find_uniq_filename"); length= dirname_part(buff, name, &buf_length); @@ -1858,15 +1863,15 @@ static int find_uniq_filename(char *name) end= strend(start); *end='.'; - length= (size_t) (end-start+1); + length= (size_t) (end - start + 1); - if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT)))) + if (!(dir_info= my_dir(buff,MYF(MY_DONT_SORT)))) { // This shouldn't happen strmov(end,".1"); // use name+1 - DBUG_RETURN(0); + DBUG_RETURN(1); } file_info= dir_info->dir_entry; - for (i=dir_info->number_off_files ; i-- ; file_info++) + for (i= dir_info->number_off_files ; i-- ; file_info++) { if (bcmp((uchar*) file_info->name, (uchar*) start, length) == 0 && test_if_number(file_info->name+length, &number,0)) @@ -1876,9 +1881,44 @@ static int find_uniq_filename(char *name) } my_dirend(dir_info); + /* check if reached the maximum possible extension number */ + if ((max_found == MAX_LOG_UNIQUE_FN_EXT)) + { + sql_print_error("Log filename extension number exhausted: %06lu. \ +Please fix this by archiving old logs and \ +updating the index files.", max_found); + error= 1; + goto end; + } + + next= max_found + 1; + sprintf(ext_buf, "%06lu", next); *end++='.'; - sprintf(end,"%06ld",max_found+1); - DBUG_RETURN(0); + + /* + Check if the generated extension size + the file name exceeds the + buffer size used. If one did not check this, then the filename might be + truncated, resulting in error. + */ + if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN)) + { + sql_print_error("Log filename too large: %s%s (%d). \ +Please fix this by archiving old logs and updating the \ +index files.", name, ext_buf, (strlen(ext_buf) + (end - name))); + error= 1; + goto end; + } + + sprintf(end, "%06lu", next); + + /* print warning if reaching the end of available extensions. */ + if ((next > (MAX_LOG_UNIQUE_FN_EXT - LOG_WARN_UNIQUE_FN_EXT_LEFT))) + sql_print_warning("Next log extension: %lu. \ +Remaining log filename extensions: %lu. \ +Please consider archiving some logs.", next, (MAX_LOG_UNIQUE_FN_EXT - next)); + +end: + DBUG_RETURN(error); } @@ -2077,6 +2117,13 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name) { if (find_uniq_filename(new_name)) { + /* + This should be treated as error once propagation of error further + up in the stack gets proper handling. + */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE), + log_name); sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name); return 1; } @@ -4739,11 +4786,11 @@ void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg) @retval 1 String is a number @retval - 0 Error + 0 String is not a number */ static bool test_if_number(register const char *str, - long *res, bool allow_wildcards) + ulong *res, bool allow_wildcards) { reg2 int flag; const char *start; diff --git a/sql/log.h b/sql/log.h index d306d6f7182..3c2ccc521cc 100644 --- a/sql/log.h +++ b/sql/log.h @@ -121,6 +121,19 @@ extern TC_LOG_DUMMY tc_log_dummy; #define LOG_CLOSE_TO_BE_OPENED 2 #define LOG_CLOSE_STOP_EVENT 4 +/* + Maximum unique log filename extension. + Note: setting to 0x7FFFFFFF due to atol windows + overflow/truncate. + */ +#define MAX_LOG_UNIQUE_FN_EXT 0x7FFFFFFF + +/* + Number of warnings that will be printed to error log + before extension number is exhausted. +*/ +#define LOG_WARN_UNIQUE_FN_EXT_LEFT 1000 + class Relay_log_info; typedef struct st_log_info From ba98c882728a6ea3f03566f3548c7c40a21567b3 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 29 Sep 2009 15:12:43 +0100 Subject: [PATCH 033/274] BUG#42928: binlog-format setting prevents server from start if binary logging is disabled NOTE: this is the backport to next-mr. If one sets binlog-format but does NOT enable binary log, server refuses to start up. The following messages appears in the error log: 090217 12:47:14 [ERROR] You need to use --log-bin to make --binlog-format work. 090217 12:47:14 [ERROR] Aborting This patch addresses this by making the server not to bail out if the binlog-format is set without the log-bin option. Additionally, the specified binlog-format is stored, in the global system variable "binlog_format", and a warning is printed instead of an error. --- sql/mysqld.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9ae3db4762b..513302b6aec 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3827,9 +3827,10 @@ with --log-bin instead."); { if (opt_binlog_format_id != BINLOG_FORMAT_UNSPEC) { - sql_print_error("You need to use --log-bin to make " - "--binlog-format work."); - unireg_abort(1); + sql_print_warning("You need to use --log-bin to make " + "--binlog-format work."); + + global_system_variables.binlog_format= opt_binlog_format_id; } else { From 25162d0166206ee4819ece2161d26caa01153723 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Tue, 29 Sep 2009 15:18:44 +0100 Subject: [PATCH 034/274] BUG#43789 different master/slave table defs cause crash: text/varchar null vs not null NOTE: Backporting the patch to next-mr. The replication was generating corrupted data, warning messages on Valgrind and aborting on debug mode while replicating a "null" to "not null" field. Specifically the unpack_row routine, was considering the slave's table definition and trying to retrieve a field value, where there was nothing to be retrieved, ignoring the fact that the value was defined as "null" by the master. To fix the problem, we proceed as follows: 1 - If it is not STRICT sql_mode, implicit default values are used, regardless if it is multi-row or single-row statement. 2 - However, if it is STRICT mode, then a we do what follows: 2.1 If it is a transactional engine, we do a rollback on the first NULL that is to be set into a NOT NULL column and return an error. 2.2 If it is a non-transactional engine and it is the first row to be inserted with multi-row, we also return the error. Otherwise, we proceed with the execution, use implicit default values and print out warning messages. Unfortunately, the current patch cannot mimic the behavior showed by the master for updates on multi-tables and multi-row inserts. This happens because such statements are unfolded in different row events. For instance, considering the following updates and strict mode: (master) create table t1 (a int); create table t2 (a int not null); insert into t1 values (1); insert into t2 values (2); update t1, t2 SET t1.a=10, t2.a=NULL; t1 would have (10) and t2 would have (0) as this would be handled as a multi-row update. On the other hand, if we had the following updates: (master) create table t1 (a int); create table t2 (a int); (slave) create table t1 (a int); create table t2 (a int not null); (master) insert into t1 values (1); insert into t2 values (2); update t1, t2 SET t1.a=10, t2.a=NULL; On the master t1 would have (10) and t2 would have (NULL). On the slave, t1 would have (10) but the update on t1 would fail. --- mysql-test/extra/rpl_tests/rpl_not_null.test | 364 ++++++++++++++++++ .../suite/rpl/r/rpl_not_null_innodb.result | 202 ++++++++++ .../suite/rpl/r/rpl_not_null_myisam.result | 202 ++++++++++ .../suite/rpl/t/rpl_not_null_innodb.test | 19 + .../suite/rpl/t/rpl_not_null_myisam.test | 18 + sql/log_event.cc | 17 +- sql/log_event.h | 8 +- sql/rpl_record.cc | 56 ++- sql/rpl_record.h | 6 +- 9 files changed, 873 insertions(+), 19 deletions(-) create mode 100644 mysql-test/extra/rpl_tests/rpl_not_null.test create mode 100644 mysql-test/suite/rpl/r/rpl_not_null_innodb.result create mode 100644 mysql-test/suite/rpl/r/rpl_not_null_myisam.result create mode 100644 mysql-test/suite/rpl/t/rpl_not_null_innodb.test create mode 100644 mysql-test/suite/rpl/t/rpl_not_null_myisam.test diff --git a/mysql-test/extra/rpl_tests/rpl_not_null.test b/mysql-test/extra/rpl_tests/rpl_not_null.test new file mode 100644 index 00000000000..88f37f9a95e --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_not_null.test @@ -0,0 +1,364 @@ +################################################################################# +# This test checks if the replication between "null" fields to either "null" +# fields or "not null" fields works properly. In the first case, the execution +# should work fine. In the second case, it may fail according to the sql_mode +# being used. +# +# The test is devided in three main parts: +# +# 1 - NULL --> NULL (no failures) +# 2 - NULL --> NOT NULL ( sql-mode = STRICT and failures) +# 3 - NULL --> NOT NULL ( sql-mode != STRICT and no failures) +# +################################################################################# +connection master; + +SET SQL_LOG_BIN= 0; +eval CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL, +`c` INT DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; + +eval CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; + +eval CREATE TABLE t3(`a` INT, `b` DATE DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; + +eval CREATE TABLE t4(`a` INT, `b` DATE DEFAULT NULL, +`c` INT DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +SET SQL_LOG_BIN= 1; + +connection slave; + +eval CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL, +`c` INT DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; + +eval CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; + +eval CREATE TABLE t3(`a` INT, `b` DATE DEFAULT '0000-00-00', +`c` INT DEFAULT 500, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; + +eval CREATE TABLE t4(`a` INT, `b` DATE DEFAULT '0000-00-00', +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; + +--echo ************* EXECUTION WITH INSERTS ************* +connection master; +INSERT INTO t1(a,b,c) VALUES (1, null, 1); +INSERT INTO t1(a,b,c) VALUES (2,'1111-11-11', 2); +INSERT INTO t1(a,b) VALUES (3, null); +INSERT INTO t1(a,c) VALUES (4, 4); +INSERT INTO t1(a) VALUES (5); + +INSERT INTO t2(a,b) VALUES (1, null); +INSERT INTO t2(a,b) VALUES (2,'1111-11-11'); +INSERT INTO t2(a) VALUES (3); + +INSERT INTO t3(a,b) VALUES (1, null); +INSERT INTO t3(a,b) VALUES (2,'1111-11-11'); +INSERT INTO t3(a) VALUES (3); + +INSERT INTO t4(a,b,c) VALUES (1, null, 1); +INSERT INTO t4(a,b,c) VALUES (2,'1111-11-11', 2); +INSERT INTO t4(a,b) VALUES (3, null); +INSERT INTO t4(a,c) VALUES (4, 4); +INSERT INTO t4(a) VALUES (5); + +--echo ************* SHOWING THE RESULT SETS WITH INSERTS ************* +sync_slave_with_master; + +--echo TABLES t1 and t2 must be equal otherwise an error will be thrown. +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +let $diff_table_1=master:test.t2; +let $diff_table_2=slave:test.t2; +source include/diff_tables.inc; + +--echo TABLES t2 and t3 must be different. +connection master; +SELECT * FROM t3; +connection slave; +SELECT * FROM t3; +connection master; +SELECT * FROM t4; +connection slave; +SELECT * FROM t4; + +--echo ************* EXECUTION WITH UPDATES and REPLACES ************* +connection master; +DELETE FROM t1; +INSERT INTO t1(a,b,c) VALUES (1,'1111-11-11', 1); +REPLACE INTO t1(a,b,c) VALUES (2,'1111-11-11', 2); +UPDATE t1 set b= NULL, c= 300 where a= 1; +REPLACE INTO t1(a,b,c) VALUES (2, NULL, 300); + +--echo ************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES ************* +sync_slave_with_master; + +--echo TABLES t1 and t2 must be equal otherwise an error will be thrown. +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +--echo ************* CLEANING ************* +connection master; + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; + +sync_slave_with_master; + +connection master; + +SET SQL_LOG_BIN= 0; +eval CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT NULL, `c` BIT DEFAULT NULL, +PRIMARY KEY (`a`)) ENGINE= $engine; +SET SQL_LOG_BIN= 1; + +connection slave; + +eval CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT b'01', `c` BIT DEFAULT NULL, +PRIMARY KEY (`a`)) ENGINE= $engine; + +--echo ************* EXECUTION WITH INSERTS ************* +connection master; +INSERT INTO t1(a,b,c) VALUES (1, null, b'01'); +INSERT INTO t1(a,b,c) VALUES (2,b'00', b'01'); +INSERT INTO t1(a,b) VALUES (3, null); +INSERT INTO t1(a,c) VALUES (4, b'01'); +INSERT INTO t1(a) VALUES (5); + +--echo ************* SHOWING THE RESULT SETS WITH INSERTS ************* +--echo TABLES t1 and t2 must be different. +sync_slave_with_master; +connection master; +SELECT a,b+0,c+0 FROM t1; +connection slave; +SELECT a,b+0,c+0 FROM t1; + +--echo ************* EXECUTION WITH UPDATES and REPLACES ************* +connection master; +DELETE FROM t1; +INSERT INTO t1(a,b,c) VALUES (1,b'00', b'01'); +REPLACE INTO t1(a,b,c) VALUES (2,b'00',b'01'); +UPDATE t1 set b= NULL, c= b'00' where a= 1; +REPLACE INTO t1(a,b,c) VALUES (2, NULL, b'00'); + +--echo ************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES ************* +--echo TABLES t1 and t2 must be equal otherwise an error will be thrown. +sync_slave_with_master; +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +connection master; + +DROP TABLE t1; + +sync_slave_with_master; + +--echo ################################################################################ +--echo # NULL ---> NOT NULL (STRICT MODE) +--echo # UNCOMMENT THIS AFTER FIXING BUG#43992 +--echo ################################################################################ +#connection slave; +#SET GLOBAL sql_mode="TRADITIONAL"; +# +#STOP SLAVE; +#--source include/wait_for_slave_to_stop.inc +#START SLAVE; +#--source include/wait_for_slave_to_start.inc +# +#let $y=0; +#while (`select $y < 6`) +#{ +# connection master; +# +# SET SQL_LOG_BIN= 0; +# eval CREATE TABLE t1(`a` INT NOT NULL, `b` INT, +# PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +# eval CREATE TABLE t2(`a` INT NOT NULL, `b` INT, +# PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +# eval CREATE TABLE t3(`a` INT NOT NULL, `b` INT, +# PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +# SET SQL_LOG_BIN= 1; +# +# connection slave; +# +# eval CREATE TABLE t1(`a` INT NOT NULL, `b` INT NOT NULL, +# `c` INT NOT NULL, +# PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +# eval CREATE TABLE t2(`a` INT NOT NULL, `b` INT NOT NULL, +# `c` INT, +# PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +# eval CREATE TABLE t3(`a` INT NOT NULL, `b` INT NOT NULL, +# `c` INT DEFAULT 500, +# PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +# +# if (`select $y=0`) +# { +# --echo ************* EXECUTION WITH INSERTS ************* +# connection master; +# INSERT INTO t1(a) VALUES (1); +# } +# +# if (`select $y=1`) +# { +# --echo ************* EXECUTION WITH INSERTS ************* +# connection master; +# INSERT INTO t1(a, b) VALUES (1, NULL); +# } +# +# if (`select $y=2`) +# { +# --echo ************* EXECUTION WITH UPDATES ************* +# connection master; +# INSERT INTO t3(a, b) VALUES (1, 1); +# INSERT INTO t3(a, b) VALUES (2, 1); +# UPDATE t3 SET b = NULL where a= 1; +# } +# +# if (`select $y=3`) +# { +# --echo ************* EXECUTION WITH INSERTS/REPLACES ************* +# connection master; +# REPLACE INTO t3(a, b) VALUES (1, null); +# } +# +# if (`select $y=4`) +# { +# --echo ************* EXECUTION WITH UPDATES/REPLACES ************* +# connection master; +# INSERT INTO t3(a, b) VALUES (1, 1); +# REPLACE INTO t3(a, b) VALUES (1, null); +# } +# +# if (`select $y=5`) +# { +# --echo ************* EXECUTION WITH MULTI-ROW INSERTS ************* +# connection master; +# +# SET SQL_LOG_BIN= 0; +# INSERT INTO t2(a, b) VALUES (1, 1); +# INSERT INTO t2(a, b) VALUES (2, 1); +# INSERT INTO t2(a, b) VALUES (3, null); +# INSERT INTO t2(a, b) VALUES (4, 1); +# INSERT INTO t2(a, b) VALUES (5, 1); +# SET SQL_LOG_BIN= 1; +# +# INSERT INTO t2 SELECT a + 10, b from t2; +# --echo The statement below is just executed to stop processing +# INSERT INTO t1(a) VALUES (1); +# } +# +# --echo ************* SHOWING THE RESULT SETS ************* +# connection slave; +# --source include/wait_for_slave_sql_to_stop.inc +# connection master; +# SELECT * FROM t1; +# connection slave; +# SELECT * FROM t1; +# connection master; +# SELECT * FROM t2; +# connection slave; +# SELECT * FROM t2; +# connection master; +# SELECT * FROM t3; +# connection slave; +# SELECT * FROM t3; +# --source include/reset_master_and_slave.inc +# +# connection master; +# +# DROP TABLE t1; +# DROP TABLE t2; +# DROP TABLE t3; +# +# sync_slave_with_master; +# +# inc $y; +#} +#connection slave; +#SET GLOBAL sql_mode=""; +# +#STOP SLAVE; +#source include/wait_for_slave_to_stop.inc; +#START SLAVE; +#--source include/wait_for_slave_to_start.inc + +--echo ################################################################################ +--echo # NULL ---> NOT NULL (NON-STRICT MODE) +--echo ################################################################################ +connection master; + +SET SQL_LOG_BIN= 0; +eval CREATE TABLE t1(`a` INT NOT NULL, `b` INT, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +eval CREATE TABLE t2(`a` INT NOT NULL, `b` INT, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +eval CREATE TABLE t3(`a` INT NOT NULL, `b` INT, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +SET SQL_LOG_BIN= 1; + +connection slave; + +eval CREATE TABLE t1(`a` INT NOT NULL, `b` INT NOT NULL, +`c` INT NOT NULL, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +eval CREATE TABLE t2(`a` INT NOT NULL, `b` INT NOT NULL, +`c` INT, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; +eval CREATE TABLE t3(`a` INT NOT NULL, `b` INT NOT NULL, +`c` INT DEFAULT 500, +PRIMARY KEY(`a`)) ENGINE=$engine DEFAULT CHARSET=LATIN1; + +--echo ************* EXECUTION WITH INSERTS ************* +connection master; +INSERT INTO t1(a) VALUES (1); +INSERT INTO t1(a, b) VALUES (2, NULL); +INSERT INTO t1(a, b) VALUES (3, 1); + +INSERT INTO t2(a) VALUES (1); +INSERT INTO t2(a, b) VALUES (2, NULL); +INSERT INTO t2(a, b) VALUES (3, 1); + +INSERT INTO t3(a) VALUES (1); +INSERT INTO t3(a, b) VALUES (2, NULL); +INSERT INTO t3(a, b) VALUES (3, 1); +INSERT INTO t3(a, b) VALUES (4, 1); +REPLACE INTO t3(a, b) VALUES (5, null); + +REPLACE INTO t3(a, b) VALUES (3, null); +UPDATE t3 SET b = NULL where a = 4; + +--echo ************* SHOWING THE RESULT SETS ************* +connection master; +sync_slave_with_master; + +connection master; +SELECT * FROM t1; +connection slave; +SELECT * FROM t1; +connection master; +SELECT * FROM t2; +connection slave; +SELECT * FROM t2; +connection master; +SELECT * FROM t3; +connection slave; +SELECT * FROM t3; + +connection master; + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; + +sync_slave_with_master; diff --git a/mysql-test/suite/rpl/r/rpl_not_null_innodb.result b/mysql-test/suite/rpl/r/rpl_not_null_innodb.result new file mode 100644 index 00000000000..7717beb0a47 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_not_null_innodb.result @@ -0,0 +1,202 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +SET SQL_LOG_BIN= 0; +CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL, +`c` INT DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t3(`a` INT, `b` DATE DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t4(`a` INT, `b` DATE DEFAULT NULL, +`c` INT DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +SET SQL_LOG_BIN= 1; +CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL, +`c` INT DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t3(`a` INT, `b` DATE DEFAULT '0000-00-00', +`c` INT DEFAULT 500, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t4(`a` INT, `b` DATE DEFAULT '0000-00-00', +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +************* EXECUTION WITH INSERTS ************* +INSERT INTO t1(a,b,c) VALUES (1, null, 1); +INSERT INTO t1(a,b,c) VALUES (2,'1111-11-11', 2); +INSERT INTO t1(a,b) VALUES (3, null); +INSERT INTO t1(a,c) VALUES (4, 4); +INSERT INTO t1(a) VALUES (5); +INSERT INTO t2(a,b) VALUES (1, null); +INSERT INTO t2(a,b) VALUES (2,'1111-11-11'); +INSERT INTO t2(a) VALUES (3); +INSERT INTO t3(a,b) VALUES (1, null); +INSERT INTO t3(a,b) VALUES (2,'1111-11-11'); +INSERT INTO t3(a) VALUES (3); +INSERT INTO t4(a,b,c) VALUES (1, null, 1); +INSERT INTO t4(a,b,c) VALUES (2,'1111-11-11', 2); +INSERT INTO t4(a,b) VALUES (3, null); +INSERT INTO t4(a,c) VALUES (4, 4); +INSERT INTO t4(a) VALUES (5); +************* SHOWING THE RESULT SETS WITH INSERTS ************* +TABLES t1 and t2 must be equal otherwise an error will be thrown. +Comparing tables master:test.t1 and slave:test.t1 +Comparing tables master:test.t2 and slave:test.t2 +TABLES t2 and t3 must be different. +SELECT * FROM t3; +a b +1 NULL +2 1111-11-11 +3 NULL +SELECT * FROM t3; +a b c +1 NULL 500 +2 1111-11-11 500 +3 NULL 500 +SELECT * FROM t4; +a b c +1 NULL 1 +2 1111-11-11 2 +3 NULL NULL +4 NULL 4 +5 NULL NULL +SELECT * FROM t4; +a b +1 NULL +2 1111-11-11 +3 NULL +4 NULL +5 NULL +************* EXECUTION WITH UPDATES and REPLACES ************* +DELETE FROM t1; +INSERT INTO t1(a,b,c) VALUES (1,'1111-11-11', 1); +REPLACE INTO t1(a,b,c) VALUES (2,'1111-11-11', 2); +UPDATE t1 set b= NULL, c= 300 where a= 1; +REPLACE INTO t1(a,b,c) VALUES (2, NULL, 300); +************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES ************* +TABLES t1 and t2 must be equal otherwise an error will be thrown. +Comparing tables master:test.t1 and slave:test.t1 +************* CLEANING ************* +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +SET SQL_LOG_BIN= 0; +CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT NULL, `c` BIT DEFAULT NULL, +PRIMARY KEY (`a`)) ENGINE= Innodb; +SET SQL_LOG_BIN= 1; +CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT b'01', `c` BIT DEFAULT NULL, +PRIMARY KEY (`a`)) ENGINE= Innodb; +************* EXECUTION WITH INSERTS ************* +INSERT INTO t1(a,b,c) VALUES (1, null, b'01'); +INSERT INTO t1(a,b,c) VALUES (2,b'00', b'01'); +INSERT INTO t1(a,b) VALUES (3, null); +INSERT INTO t1(a,c) VALUES (4, b'01'); +INSERT INTO t1(a) VALUES (5); +************* SHOWING THE RESULT SETS WITH INSERTS ************* +TABLES t1 and t2 must be different. +SELECT a,b+0,c+0 FROM t1; +a b+0 c+0 +1 NULL 1 +2 0 1 +3 NULL NULL +4 NULL 1 +5 NULL NULL +SELECT a,b+0,c+0 FROM t1; +a b+0 c+0 +1 NULL 1 +2 0 1 +3 NULL NULL +4 NULL 1 +5 NULL NULL +************* EXECUTION WITH UPDATES and REPLACES ************* +DELETE FROM t1; +INSERT INTO t1(a,b,c) VALUES (1,b'00', b'01'); +REPLACE INTO t1(a,b,c) VALUES (2,b'00',b'01'); +UPDATE t1 set b= NULL, c= b'00' where a= 1; +REPLACE INTO t1(a,b,c) VALUES (2, NULL, b'00'); +************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES ************* +TABLES t1 and t2 must be equal otherwise an error will be thrown. +Comparing tables master:test.t1 and slave:test.t1 +DROP TABLE t1; +################################################################################ +# NULL ---> NOT NULL (STRICT MODE) +# UNCOMMENT THIS AFTER FIXING BUG#43992 +################################################################################ +################################################################################ +# NULL ---> NOT NULL (NON-STRICT MODE) +################################################################################ +SET SQL_LOG_BIN= 0; +CREATE TABLE t1(`a` INT NOT NULL, `b` INT, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t2(`a` INT NOT NULL, `b` INT, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t3(`a` INT NOT NULL, `b` INT, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +SET SQL_LOG_BIN= 1; +CREATE TABLE t1(`a` INT NOT NULL, `b` INT NOT NULL, +`c` INT NOT NULL, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t2(`a` INT NOT NULL, `b` INT NOT NULL, +`c` INT, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +CREATE TABLE t3(`a` INT NOT NULL, `b` INT NOT NULL, +`c` INT DEFAULT 500, +PRIMARY KEY(`a`)) ENGINE=Innodb DEFAULT CHARSET=LATIN1; +************* EXECUTION WITH INSERTS ************* +INSERT INTO t1(a) VALUES (1); +INSERT INTO t1(a, b) VALUES (2, NULL); +INSERT INTO t1(a, b) VALUES (3, 1); +INSERT INTO t2(a) VALUES (1); +INSERT INTO t2(a, b) VALUES (2, NULL); +INSERT INTO t2(a, b) VALUES (3, 1); +INSERT INTO t3(a) VALUES (1); +INSERT INTO t3(a, b) VALUES (2, NULL); +INSERT INTO t3(a, b) VALUES (3, 1); +INSERT INTO t3(a, b) VALUES (4, 1); +REPLACE INTO t3(a, b) VALUES (5, null); +REPLACE INTO t3(a, b) VALUES (3, null); +UPDATE t3 SET b = NULL where a = 4; +************* SHOWING THE RESULT SETS ************* +SELECT * FROM t1; +a b +1 NULL +2 NULL +3 1 +SELECT * FROM t1; +a b c +1 0 0 +2 0 0 +3 1 0 +SELECT * FROM t2; +a b +1 NULL +2 NULL +3 1 +SELECT * FROM t2; +a b c +1 0 NULL +2 0 NULL +3 1 NULL +SELECT * FROM t3; +a b +1 NULL +2 NULL +3 NULL +4 NULL +5 NULL +SELECT * FROM t3; +a b c +1 0 500 +2 0 500 +3 0 500 +4 0 500 +5 0 500 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; diff --git a/mysql-test/suite/rpl/r/rpl_not_null_myisam.result b/mysql-test/suite/rpl/r/rpl_not_null_myisam.result new file mode 100644 index 00000000000..57a015367bb --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_not_null_myisam.result @@ -0,0 +1,202 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +SET SQL_LOG_BIN= 0; +CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL, +`c` INT DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t3(`a` INT, `b` DATE DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t4(`a` INT, `b` DATE DEFAULT NULL, +`c` INT DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +SET SQL_LOG_BIN= 1; +CREATE TABLE t1(`a` INT, `b` DATE DEFAULT NULL, +`c` INT DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t2(`a` INT, `b` DATE DEFAULT NULL, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t3(`a` INT, `b` DATE DEFAULT '0000-00-00', +`c` INT DEFAULT 500, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t4(`a` INT, `b` DATE DEFAULT '0000-00-00', +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +************* EXECUTION WITH INSERTS ************* +INSERT INTO t1(a,b,c) VALUES (1, null, 1); +INSERT INTO t1(a,b,c) VALUES (2,'1111-11-11', 2); +INSERT INTO t1(a,b) VALUES (3, null); +INSERT INTO t1(a,c) VALUES (4, 4); +INSERT INTO t1(a) VALUES (5); +INSERT INTO t2(a,b) VALUES (1, null); +INSERT INTO t2(a,b) VALUES (2,'1111-11-11'); +INSERT INTO t2(a) VALUES (3); +INSERT INTO t3(a,b) VALUES (1, null); +INSERT INTO t3(a,b) VALUES (2,'1111-11-11'); +INSERT INTO t3(a) VALUES (3); +INSERT INTO t4(a,b,c) VALUES (1, null, 1); +INSERT INTO t4(a,b,c) VALUES (2,'1111-11-11', 2); +INSERT INTO t4(a,b) VALUES (3, null); +INSERT INTO t4(a,c) VALUES (4, 4); +INSERT INTO t4(a) VALUES (5); +************* SHOWING THE RESULT SETS WITH INSERTS ************* +TABLES t1 and t2 must be equal otherwise an error will be thrown. +Comparing tables master:test.t1 and slave:test.t1 +Comparing tables master:test.t2 and slave:test.t2 +TABLES t2 and t3 must be different. +SELECT * FROM t3; +a b +1 NULL +2 1111-11-11 +3 NULL +SELECT * FROM t3; +a b c +1 NULL 500 +2 1111-11-11 500 +3 NULL 500 +SELECT * FROM t4; +a b c +1 NULL 1 +2 1111-11-11 2 +3 NULL NULL +4 NULL 4 +5 NULL NULL +SELECT * FROM t4; +a b +1 NULL +2 1111-11-11 +3 NULL +4 NULL +5 NULL +************* EXECUTION WITH UPDATES and REPLACES ************* +DELETE FROM t1; +INSERT INTO t1(a,b,c) VALUES (1,'1111-11-11', 1); +REPLACE INTO t1(a,b,c) VALUES (2,'1111-11-11', 2); +UPDATE t1 set b= NULL, c= 300 where a= 1; +REPLACE INTO t1(a,b,c) VALUES (2, NULL, 300); +************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES ************* +TABLES t1 and t2 must be equal otherwise an error will be thrown. +Comparing tables master:test.t1 and slave:test.t1 +************* CLEANING ************* +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +SET SQL_LOG_BIN= 0; +CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT NULL, `c` BIT DEFAULT NULL, +PRIMARY KEY (`a`)) ENGINE= MyISAM; +SET SQL_LOG_BIN= 1; +CREATE TABLE t1 (`a` INT, `b` BIT DEFAULT b'01', `c` BIT DEFAULT NULL, +PRIMARY KEY (`a`)) ENGINE= MyISAM; +************* EXECUTION WITH INSERTS ************* +INSERT INTO t1(a,b,c) VALUES (1, null, b'01'); +INSERT INTO t1(a,b,c) VALUES (2,b'00', b'01'); +INSERT INTO t1(a,b) VALUES (3, null); +INSERT INTO t1(a,c) VALUES (4, b'01'); +INSERT INTO t1(a) VALUES (5); +************* SHOWING THE RESULT SETS WITH INSERTS ************* +TABLES t1 and t2 must be different. +SELECT a,b+0,c+0 FROM t1; +a b+0 c+0 +1 NULL 1 +2 0 1 +3 NULL NULL +4 NULL 1 +5 NULL NULL +SELECT a,b+0,c+0 FROM t1; +a b+0 c+0 +1 NULL 1 +2 0 1 +3 NULL NULL +4 NULL 1 +5 NULL NULL +************* EXECUTION WITH UPDATES and REPLACES ************* +DELETE FROM t1; +INSERT INTO t1(a,b,c) VALUES (1,b'00', b'01'); +REPLACE INTO t1(a,b,c) VALUES (2,b'00',b'01'); +UPDATE t1 set b= NULL, c= b'00' where a= 1; +REPLACE INTO t1(a,b,c) VALUES (2, NULL, b'00'); +************* SHOWING THE RESULT SETS WITH UPDATES and REPLACES ************* +TABLES t1 and t2 must be equal otherwise an error will be thrown. +Comparing tables master:test.t1 and slave:test.t1 +DROP TABLE t1; +################################################################################ +# NULL ---> NOT NULL (STRICT MODE) +# UNCOMMENT THIS AFTER FIXING BUG#43992 +################################################################################ +################################################################################ +# NULL ---> NOT NULL (NON-STRICT MODE) +################################################################################ +SET SQL_LOG_BIN= 0; +CREATE TABLE t1(`a` INT NOT NULL, `b` INT, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t2(`a` INT NOT NULL, `b` INT, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t3(`a` INT NOT NULL, `b` INT, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +SET SQL_LOG_BIN= 1; +CREATE TABLE t1(`a` INT NOT NULL, `b` INT NOT NULL, +`c` INT NOT NULL, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t2(`a` INT NOT NULL, `b` INT NOT NULL, +`c` INT, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +CREATE TABLE t3(`a` INT NOT NULL, `b` INT NOT NULL, +`c` INT DEFAULT 500, +PRIMARY KEY(`a`)) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; +************* EXECUTION WITH INSERTS ************* +INSERT INTO t1(a) VALUES (1); +INSERT INTO t1(a, b) VALUES (2, NULL); +INSERT INTO t1(a, b) VALUES (3, 1); +INSERT INTO t2(a) VALUES (1); +INSERT INTO t2(a, b) VALUES (2, NULL); +INSERT INTO t2(a, b) VALUES (3, 1); +INSERT INTO t3(a) VALUES (1); +INSERT INTO t3(a, b) VALUES (2, NULL); +INSERT INTO t3(a, b) VALUES (3, 1); +INSERT INTO t3(a, b) VALUES (4, 1); +REPLACE INTO t3(a, b) VALUES (5, null); +REPLACE INTO t3(a, b) VALUES (3, null); +UPDATE t3 SET b = NULL where a = 4; +************* SHOWING THE RESULT SETS ************* +SELECT * FROM t1; +a b +1 NULL +2 NULL +3 1 +SELECT * FROM t1; +a b c +1 0 0 +2 0 0 +3 1 0 +SELECT * FROM t2; +a b +1 NULL +2 NULL +3 1 +SELECT * FROM t2; +a b c +1 0 NULL +2 0 NULL +3 1 NULL +SELECT * FROM t3; +a b +1 NULL +2 NULL +3 NULL +4 NULL +5 NULL +SELECT * FROM t3; +a b c +1 0 500 +2 0 500 +3 0 500 +4 0 500 +5 0 500 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; diff --git a/mysql-test/suite/rpl/t/rpl_not_null_innodb.test b/mysql-test/suite/rpl/t/rpl_not_null_innodb.test new file mode 100644 index 00000000000..dca0ea6589c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_not_null_innodb.test @@ -0,0 +1,19 @@ +################################################################################# +# This test checks if the replication between "null" fields to either "null" +# fields or "not null" fields works properly. In the first case, the execution +# should work fine. In the second case, it may fail according to the sql_mode +# being used. +# +# The test is devided in three main parts: +# +# 1 - NULL --> NULL (no failures) +# 2 - NULL --> NOT NULL ( sql-mode = STRICT and failures) +# 3 - NULL --> NOT NULL ( sql-mode != STRICT and no failures) +# +################################################################################# +--source include/master-slave.inc +--source include/have_innodb.inc +--source include/have_binlog_format_row.inc + +let $engine=Innodb; +--source extra/rpl_tests/rpl_not_null.test diff --git a/mysql-test/suite/rpl/t/rpl_not_null_myisam.test b/mysql-test/suite/rpl/t/rpl_not_null_myisam.test new file mode 100644 index 00000000000..0c036f5bfd7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_not_null_myisam.test @@ -0,0 +1,18 @@ +################################################################################# +# This test checks if the replication between "null" fields to either "null" +# fields or "not null" fields works properly. In the first case, the execution +# should work fine. In the second case, it may fail according to the sql_mode +# being used. +# +# The test is devided in three main parts: +# +# 1 - NULL --> NULL (no failures) +# 2 - NULL --> NOT NULL ( sql-mode = STRICT and failures) +# 3 - NULL --> NOT NULL ( sql-mode != STRICT and no failures) +# +################################################################################# +--source include/master-slave.inc +--source include/have_binlog_format_row.inc + +let $engine=MyISAM; +--source extra/rpl_tests/rpl_not_null.test diff --git a/sql/log_event.cc b/sql/log_event.cc index d595f00bffd..eeed50f697d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8444,16 +8444,17 @@ Rows_log_event::write_row(const Relay_log_info *const rli, auto_afree_ptr key(NULL); /* fill table->record[0] with default values */ - + bool abort_on_warnings= (rli->sql_thd->variables.sql_mode & + (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); if ((error= prepare_record(table, m_width, table->file->ht->db_type != DB_TYPE_NDBCLUSTER, - (rli->sql_thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES))))) + abort_on_warnings, m_curr_row == m_rows_buf))) DBUG_RETURN(error); /* unpack row into table->record[0] */ - error= unpack_current_row(rli); // TODO: how to handle errors? + if ((error= unpack_current_row(rli, abort_on_warnings))) + DBUG_RETURN(error); + if (m_curr_row == m_rows_buf) { /* this is the first row to be inserted, we estimate the rows with @@ -9250,8 +9251,12 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) store_record(m_table,record[1]); + bool abort_on_warnings= (rli->sql_thd->variables.sql_mode & + (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); m_curr_row= m_curr_row_end; - error= unpack_current_row(rli); // this also updates m_curr_row_end + /* this also updates m_curr_row_end */ + if ((error= unpack_current_row(rli, abort_on_warnings))) + return error; /* Now we have the right row to update. The old row (the one we're diff --git a/sql/log_event.h b/sql/log_event.h index 8202dddcc76..bbcca76741c 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3541,12 +3541,16 @@ protected: int write_row(const Relay_log_info *const, const bool); // Unpack the current row into m_table->record[0] - int unpack_current_row(const Relay_log_info *const rli) + int unpack_current_row(const Relay_log_info *const rli, + const bool abort_on_warning= TRUE) { DBUG_ASSERT(m_table); + + bool first_row= (m_curr_row == m_rows_buf); ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, - &m_curr_row_end, &m_master_reclength); + &m_curr_row_end, &m_master_reclength, + abort_on_warning, first_row); if (m_curr_row_end > m_rows_end) my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0)); ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index f4768e2456a..8e80620dd2c 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -180,7 +180,8 @@ int unpack_row(Relay_log_info const *rli, TABLE *table, uint const colcnt, uchar const *const row_data, MY_BITMAP const *cols, - uchar const **const row_end, ulong *const master_reclength) + uchar const **const row_end, ulong *const master_reclength, + const bool abort_on_warning, const bool first_row) { DBUG_ENTER("unpack_row"); DBUG_ASSERT(row_data); @@ -224,8 +225,35 @@ unpack_row(Relay_log_info const *rli, /* Field...::unpack() cannot return 0 */ DBUG_ASSERT(pack_ptr != NULL); - if ((null_bits & null_mask) && f->maybe_null()) - f->set_null(); + if (null_bits & null_mask) + { + if (f->maybe_null()) + { + DBUG_PRINT("debug", ("Was NULL; null mask: 0x%x; null bits: 0x%x", + null_mask, null_bits)); + f->set_null(); + } + else + { + MYSQL_ERROR::enum_warning_level error_type= + MYSQL_ERROR::WARN_LEVEL_NOTE; + if (abort_on_warning && (table->file->has_transactions() || + first_row)) + { + error = HA_ERR_ROWS_EVENT_APPLY; + error_type= MYSQL_ERROR::WARN_LEVEL_ERROR; + } + else + { + f->set_default(); + error_type= MYSQL_ERROR::WARN_LEVEL_WARN; + } + push_warning_printf(current_thd, error_type, + ER_BAD_NULL_ERROR, + ER(ER_BAD_NULL_ERROR), + f->field_name); + } + } else { f->set_notnull(); @@ -315,7 +343,7 @@ unpack_row(Relay_log_info const *rli, */ int prepare_record(TABLE *const table, const uint skip, const bool check, - const bool abort_on_warning) + const bool abort_on_warning, const bool first_row) { DBUG_ENTER("prepare_record"); @@ -343,14 +371,24 @@ int prepare_record(TABLE *const table, if ((f->flags & NO_DEFAULT_VALUE_FLAG) && (f->real_type() != MYSQL_TYPE_ENUM)) { - push_warning_printf(current_thd, abort_on_warning? - MYSQL_ERROR::WARN_LEVEL_ERROR : - MYSQL_ERROR::WARN_LEVEL_WARN, + + MYSQL_ERROR::enum_warning_level error_type= + MYSQL_ERROR::WARN_LEVEL_NOTE; + if (abort_on_warning && (table->file->has_transactions() || + first_row)) + { + error= HA_ERR_ROWS_EVENT_APPLY; + error_type= MYSQL_ERROR::WARN_LEVEL_ERROR; + } + else + { + f->set_default(); + error_type= MYSQL_ERROR::WARN_LEVEL_WARN; + } + push_warning_printf(current_thd, error_type, ER_NO_DEFAULT_FOR_FIELD, ER(ER_NO_DEFAULT_FOR_FIELD), f->field_name); - if (abort_on_warning) - error = HA_ERR_ROWS_EVENT_APPLY; } } diff --git a/sql/rpl_record.h b/sql/rpl_record.h index ab2bcd382ca..6e8838f82b3 100644 --- a/sql/rpl_record.h +++ b/sql/rpl_record.h @@ -27,11 +27,13 @@ size_t pack_row(TABLE* table, MY_BITMAP const* cols, int unpack_row(Relay_log_info const *rli, TABLE *table, uint const colcnt, uchar const *const row_data, MY_BITMAP const *cols, - uchar const **const row_end, ulong *const master_reclength); + uchar const **const row_end, ulong *const master_reclength, + const bool abort_on_warning= TRUE, const bool first_row= TRUE); // Fill table's record[0] with default values. int prepare_record(TABLE *const table, const uint skip, const bool check, - const bool abort_on_warning= FALSE); + const bool abort_on_warning= TRUE, + const bool first_row= TRUE); #endif #endif From 0110bd04d24503d84df93d31b444586c4137c98c Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Tue, 29 Sep 2009 15:27:12 +0100 Subject: [PATCH 035/274] BUG#35542 Add option to sync master and relay log to disk after every event BUG#31665 sync_binlog should cause relay logs to be synchronized NOTE: Backporting the patch to next-mr. Add sync_relay_log option to server, this option works for relay log the same as option sync_binlog for binlog. This option also synchronize master info to disk when set to non-zero value. Original patches from Sinisa and Mark, with some modifications --- sql/log.cc | 35 +++++++++++++++++++++++------------ sql/log.h | 29 +++++++++++++++++++++++++++-- sql/mysql_priv.h | 3 ++- sql/mysqld.cc | 15 +++++++++++---- sql/rpl_mi.cc | 20 ++++++++++++++++---- sql/rpl_rli.cc | 3 ++- sql/set_var.cc | 17 +++++++++++++++++ sql/set_var.h | 21 +++++++++++++++++++++ sql/sql_repl.cc | 18 ++---------------- 9 files changed, 121 insertions(+), 40 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index 1af2f3a4ddc..12e57623add 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -49,8 +49,7 @@ LOGGER logger; -MYSQL_BIN_LOG mysql_bin_log; -ulong sync_binlog_counter= 0; +MYSQL_BIN_LOG mysql_bin_log(&sync_binlog_period); static bool test_if_number(const char *str, long *res, bool allow_wildcards); @@ -2410,9 +2409,10 @@ const char *MYSQL_LOG::generate_name(const char *log_name, -MYSQL_BIN_LOG::MYSQL_BIN_LOG() +MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period) :bytes_written(0), prepared_xids(0), file_id(1), open_count(1), need_start_event(TRUE), m_table_map_version(0), + sync_period_ptr(sync_period), is_relay_log(0), description_event_for_exec(0), description_event_for_queue(0) { @@ -3643,6 +3643,8 @@ bool MYSQL_BIN_LOG::append(Log_event* ev) } bytes_written+= ev->data_written; DBUG_PRINT("info",("max_size: %lu",max_size)); + if (flush_and_sync(0)) + goto err; if ((uint) my_b_append_tell(&log_file) > max_size) new_file_without_locking(); @@ -3673,6 +3675,8 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...) bytes_written += len; } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint))); DBUG_PRINT("info",("max_size: %lu",max_size)); + if (flush_and_sync(0)) + goto err; if ((uint) my_b_append_tell(&log_file) > max_size) new_file_without_locking(); @@ -3682,17 +3686,21 @@ err: DBUG_RETURN(error); } - -bool MYSQL_BIN_LOG::flush_and_sync() +bool MYSQL_BIN_LOG::flush_and_sync(bool *synced) { int err=0, fd=log_file.file; + if (synced) + *synced= 0; safe_mutex_assert_owner(&LOCK_log); if (flush_io_cache(&log_file)) return 1; - if (++sync_binlog_counter >= sync_binlog_period && sync_binlog_period) + uint sync_period= get_sync_period(); + if (sync_period && ++sync_counter >= sync_period) { - sync_binlog_counter= 0; + sync_counter= 0; err=my_sync(fd, MYF(MY_WME)); + if (synced) + *synced= 1; } return err; } @@ -3983,7 +3991,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, if (file == &log_file) { - error= flush_and_sync(); + error= flush_and_sync(0); if (!error) { signal_update(); @@ -4169,7 +4177,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) if (file == &log_file) // we are writing to the real log (disk) { - if (flush_and_sync()) + bool synced; + if (flush_and_sync(&synced)) goto err; signal_update(); rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); @@ -4425,7 +4434,7 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log) DBUG_ASSERT(carry == 0); if (sync_log) - flush_and_sync(); + return flush_and_sync(0); return 0; // All OK } @@ -4472,7 +4481,8 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) ev.write(&log_file); if (lock) { - if (!error && !(error= flush_and_sync())) + bool synced; + if (!error && !(error= flush_and_sync(&synced))) { signal_update(); rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); @@ -4560,7 +4570,8 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, if (incident && write_incident(thd, FALSE)) goto err; - if (flush_and_sync()) + bool synced; + if (flush_and_sync(&synced)) goto err; DBUG_EXECUTE_IF("half_binlogged_transaction", abort();); if (cache->error) // Error on read diff --git a/sql/log.h b/sql/log.h index d306d6f7182..53943b649ee 100644 --- a/sql/log.h +++ b/sql/log.h @@ -269,6 +269,18 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG ulonglong m_table_map_version; + /* pointer to the sync period variable, for binlog this will be + sync_binlog_period, for relay log this will be + sync_relay_log_period + */ + uint *sync_period_ptr; + uint sync_counter; + + inline uint get_sync_period() + { + return *sync_period_ptr; + } + int write_to_file(IO_CACHE *cache); /* This is used to start writing to a new log file. The difference from @@ -296,7 +308,7 @@ public: Format_description_log_event *description_event_for_exec, *description_event_for_queue; - MYSQL_BIN_LOG(); + MYSQL_BIN_LOG(uint *sync_period); /* note that there's no destructor ~MYSQL_BIN_LOG() ! The reason is that we don't want it to be automatically called @@ -378,7 +390,20 @@ public: bool is_active(const char* log_file_name); int update_log_index(LOG_INFO* linfo, bool need_update_threads); void rotate_and_purge(uint flags); - bool flush_and_sync(); + /** + Flush binlog cache and synchronize to disk. + + This function flushes events in binlog cache to binary log file, + it will do synchronizing according to the setting of system + variable 'sync_binlog'. If file is synchronized, @c synced will + be set to 1, otherwise 0. + + @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0 + + @retval 0 Success + @retval other Failure + */ + bool flush_and_sync(bool *synced); int purge_logs(const char *to_log, bool included, bool need_mutex, bool need_update_threads, ulonglong *decrease_log_space); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 52cfa7934c3..669942cc691 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1868,7 +1868,8 @@ extern ulong MYSQL_PLUGIN_IMPORT specialflag; #endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */ #ifdef MYSQL_SERVER extern ulong current_pid; -extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter; +extern ulong expire_logs_days; +extern uint sync_binlog_period, sync_relaylog_period; extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size; extern ulong tc_log_page_waits; extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a57ee04081f..8febc0bb7e5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -552,7 +552,8 @@ ulong max_prepared_stmt_count; */ ulong prepared_stmt_count=0; ulong thread_id=1L,current_pid; -ulong slow_launch_threads = 0, sync_binlog_period; +ulong slow_launch_threads = 0; +uint sync_binlog_period= 0, sync_relaylog_period= 0; ulong expire_logs_days = 0; ulong rpl_recovery_rank=0; const char *log_output_str= "FILE"; @@ -5667,7 +5668,8 @@ enum options_mysqld OPT_SLAVE_EXEC_MODE, OPT_GENERAL_LOG_FILE, OPT_SLOW_QUERY_LOG_FILE, - OPT_IGNORE_BUILTIN_INNODB + OPT_IGNORE_BUILTIN_INNODB, + OPT_SYNC_RELAY_LOG }; @@ -6921,8 +6923,13 @@ The minimum value for this variable is 4096.", {"sync-binlog", OPT_SYNC_BINLOG, "Synchronously flush binary log to disk after every #th event. " "Use 0 (default) to disable synchronous flushing.", - (uchar**) &sync_binlog_period, (uchar**) &sync_binlog_period, 0, GET_ULONG, - REQUIRED_ARG, 0, 0, ULONG_MAX, 0, 1, 0}, + (uchar**) &sync_binlog_period, (uchar**) &sync_binlog_period, 0, GET_UINT, + REQUIRED_ARG, 0, 0, (longlong) UINT_MAX, 0, 1, 0}, + {"sync-relay-log", OPT_SYNC_RELAY_LOG, + "Synchronously flush relay log to disk after every #th event. " + "Use 0 (default) to disable synchronous flushing.", + (uchar**) &sync_relaylog_period, (uchar**) &sync_relaylog_period, 0, GET_UINT, + REQUIRED_ARG, 0, 0, (longlong) UINT_MAX, 0, 1, 0}, {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.", (uchar**) &opt_sync_frm, (uchar**) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 5e46837e948..1bca44ac613 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -342,6 +342,7 @@ int flush_master_info(Master_info* mi, bool flush_relay_log_cache) { IO_CACHE* file = &mi->file; char lbuf[22]; + int err= 0; DBUG_ENTER("flush_master_info"); DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos)); @@ -358,9 +359,17 @@ int flush_master_info(Master_info* mi, bool flush_relay_log_cache) When we come to this place in code, relay log may or not be initialized; the caller is responsible for setting 'flush_relay_log_cache' accordingly. */ - if (flush_relay_log_cache && - flush_io_cache(mi->rli.relay_log.get_log_file())) - DBUG_RETURN(2); + if (flush_relay_log_cache) + { + IO_CACHE *log_file= mi->rli.relay_log.get_log_file(); + if (flush_io_cache(log_file)) + DBUG_RETURN(2); + + /* Sync to disk if --sync-relay-log is set */ + if (sync_relaylog_period && + my_sync(log_file->file, MY_WME)) + DBUG_RETURN(2); + } /* We flushed the relay log BEFORE the master.info file, because if we crash @@ -388,7 +397,10 @@ int flush_master_info(Master_info* mi, bool flush_relay_log_cache) mi->password, mi->port, mi->connect_retry, (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert); - DBUG_RETURN(-flush_io_cache(file)); + err= flush_io_cache(file); + if (sync_relaylog_period && !err) + err= my_sync(mi->fd, MYF(MY_WME)); + DBUG_RETURN(-err); } diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 18fbae9bb9d..37c0815fb8b 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -32,7 +32,8 @@ int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, Relay_log_info::Relay_log_info() :Slave_reporting_capability("SQL"), no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id), - info_fd(-1), cur_log_fd(-1), save_temporary_tables(0), + info_fd(-1), cur_log_fd(-1), relay_log(&sync_relaylog_period), + save_temporary_tables(0), #if HAVE_purify is_fake(FALSE), #endif diff --git a/sql/set_var.cc b/sql/set_var.cc index 5025356230c..f2b5201cf8b 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1534,6 +1534,23 @@ static bool get_unsigned(THD *thd, set_var *var, ulonglong user_max, } +bool sys_var_int_ptr::check(THD *thd, set_var *var) +{ + var->save_result.ulong_value= (ulong) var->value->val_int(); + return 0; +} + +bool sys_var_int_ptr::update(THD *thd, set_var *var) +{ + *value= (uint) var->save_result.ulong_value; + return 0; +} + +void sys_var_int_ptr::set_default(THD *thd, enum_var_type type) +{ + *value= (uint) option_limits->def_value; +} + sys_var_long_ptr:: sys_var_long_ptr(sys_var_chain *chain, const char *name_arg, ulong *value_ptr_arg, sys_after_update_func after_update_arg) diff --git a/sql/set_var.h b/sql/set_var.h index a3ed8e5be15..02c87abed88 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -175,6 +175,27 @@ public: { return (uchar*) value; } }; +/** + Unsigned int system variable class + */ +class sys_var_int_ptr :public sys_var +{ +public: + sys_var_int_ptr(sys_var_chain *chain, const char *name_arg, + uint *value_ptr_arg, + sys_after_update_func after_update_arg= NULL) + :sys_var(name_arg, after_update_arg), + value(value_ptr_arg) + { chain_sys_var(chain); } + bool check(THD *thd, set_var *var); + bool update(THD *thd, set_var *var); + void set_default(THD *thd, enum_var_type type); + SHOW_TYPE show_type() { return SHOW_INT; } + uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) + { return (uchar*) value; } +private: + uint *value; +}; /* A global ulong variable that is protected by LOCK_global_system_variables diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 4d9b7410b88..425d76c8b72 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1753,15 +1753,6 @@ public: */ }; -class sys_var_sync_binlog_period :public sys_var_long_ptr -{ -public: - sys_var_sync_binlog_period(sys_var_chain *chain, const char *name_arg, - ulong *value_ptr) - :sys_var_long_ptr(chain, name_arg,value_ptr) {} - bool update(THD *thd, set_var *var); -}; - static sys_var_chain vars = { NULL, NULL }; static sys_var_const sys_log_slave_updates(&vars, "log_slave_updates", @@ -1793,7 +1784,8 @@ static sys_var_const sys_slave_skip_errors(&vars, "slave_skip_errors", (uchar*) slave_skip_error_names); static sys_var_long_ptr sys_slave_trans_retries(&vars, "slave_transaction_retries", &slave_trans_retries); -static sys_var_sync_binlog_period sys_sync_binlog_period(&vars, "sync_binlog", &sync_binlog_period); +static sys_var_int_ptr sys_sync_binlog_period(&vars, "sync_binlog", &sync_binlog_period); +static sys_var_int_ptr sys_sync_relaylog_period(&vars, "sync_relay_log", &sync_relaylog_period); static sys_var_slave_skip_counter sys_slave_skip_counter(&vars, "sql_slave_skip_counter"); @@ -1835,12 +1827,6 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var) } -bool sys_var_sync_binlog_period::update(THD *thd, set_var *var) -{ - sync_binlog_period= (ulong) var->save_result.ulonglong_value; - return 0; -} - int init_replication_sys_vars() { if (mysql_add_sys_var_chain(vars.first, my_long_options)) From 3ab71376ceb2d5da81d3b6fb092630d0b0929d76 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Tue, 29 Sep 2009 15:40:52 +0100 Subject: [PATCH 036/274] BUG#40337 Fsyncing master and relay log to disk after every event is too slow NOTE: Backporting the patch to next-mr. The fix proposed in BUG#35542 and BUG#31665 introduces a performance issue when fsyncing the master.info, relay.info and relay-log.bin* after #th events. Although such solution has been proposed to reduce the probability of corrupted files due to a slave-crash, the performance penalty introduced by it has made the approach impractical for highly intensive workloads. In a nutshell, the option --syn-relay-log proposed in BUG#35542 and BUG#31665 simultaneously fsyncs master.info, relay-log.info and relay-log.bin* and this is the main source of performance issues. This patch introduces new options that give more control to the user on what should be fsynced and how often: 1) (--sync-master-info, integer) which syncs the master.info after #th event; 2) (--sync-relay-log, integer) which syncs the relay-log.bin* after #th events. 3) (--sync-relay-log-info, integer) which syncs the relay.info after #th transactions. To provide both performance and increased reliability, we recommend the following setup: 1) --sync-master-info = 0 eventually the operating system will fsync it; 2) --sync-relay-log = 0 eventually the operating system will fsync it; 3) --sync-relay-log-info = 1 fsyncs it after every transaction; Notice, that the previous setup does not reduce the probability of corrupted master.info and relay-log.bin*. To overcome the issue, this patch also introduces a recovery mechanism that right after restart throws away relay-log.bin* retrieved from a master and updates the master.info based on the relay.info: 4) (--relay-log-recovery, boolean) which enables a recovery mechanism that throws away relay-log.bin* after a crash. However, it can only recover the incorrect binlog file and position in master.info, if other informations (host, port password, etc) are corrupted or incorrect, then this recovery mechanism will fail to work. --- .../suite/rpl/r/rpl_flushlog_loop.result | 1 + mysql-test/suite/rpl/r/rpl_sync.result | 40 +++++ mysql-test/suite/rpl/t/rpl_sync-slave.opt | 1 + mysql-test/suite/rpl/t/rpl_sync.test | 148 ++++++++++++++++++ sql/mysql_priv.h | 4 +- sql/mysqld.cc | 26 ++- sql/rpl_mi.cc | 17 +- sql/rpl_mi.h | 9 +- sql/rpl_rli.cc | 8 +- sql/rpl_rli.h | 15 +- sql/set_var.cc | 8 +- sql/set_var.h | 4 +- sql/slave.cc | 100 +++++++++++- sql/sql_binlog.cc | 2 +- sql/sql_repl.cc | 12 +- 15 files changed, 364 insertions(+), 31 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_sync.result create mode 100644 mysql-test/suite/rpl/t/rpl_sync-slave.opt create mode 100644 mysql-test/suite/rpl/t/rpl_sync.test diff --git a/mysql-test/suite/rpl/r/rpl_flushlog_loop.result b/mysql-test/suite/rpl/r/rpl_flushlog_loop.result index 600ac44fc86..529d1db6cd6 100644 --- a/mysql-test/suite/rpl/r/rpl_flushlog_loop.result +++ b/mysql-test/suite/rpl/r/rpl_flushlog_loop.result @@ -10,6 +10,7 @@ relay_log MYSQLD_DATADIR/relay-log relay_log_index relay_log_info_file relay-log.info relay_log_purge ON +relay_log_recovery OFF relay_log_space_limit 0 stop slave; change master to master_host='127.0.0.1',master_user='root', diff --git a/mysql-test/suite/rpl/r/rpl_sync.result b/mysql-test/suite/rpl/r/rpl_sync.result new file mode 100644 index 00000000000..edc20c46140 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_sync.result @@ -0,0 +1,40 @@ +=====Configuring the enviroment=======; +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +call mtr.add_suppression('Attempting backtrace'); +call mtr.add_suppression("Recovery from master pos .* and file master-bin.000001"); +CREATE TABLE t1(a INT, PRIMARY KEY(a)) engine=innodb; +insert into t1(a) values(1); +insert into t1(a) values(2); +insert into t1(a) values(3); +=====Inserting data on the master but without the SQL Thread being running=======; +stop slave SQL_THREAD; +insert into t1(a) values(4); +insert into t1(a) values(5); +insert into t1(a) values(6); +=====Removing relay log files and crashing/recoverying the slave=======; +stop slave IO_THREAD; +SET SESSION debug="d,crash_before_rotate_relaylog"; +FLUSH LOGS; +ERROR HY000: Lost connection to MySQL server during query +=====Dumping and comparing tables=======; +start slave; +Comparing tables master:test.t1 and slave:test.t1 +=====Corrupting the master.info=======; +stop slave; +FLUSH LOGS; +insert into t1(a) values(7); +insert into t1(a) values(8); +insert into t1(a) values(9); +SET SESSION debug="d,crash_before_rotate_relaylog"; +FLUSH LOGS; +ERROR HY000: Lost connection to MySQL server during query +=====Dumping and comparing tables=======; +start slave; +Comparing tables master:test.t1 and slave:test.t1 +=====Clean up=======; +drop table t1; diff --git a/mysql-test/suite/rpl/t/rpl_sync-slave.opt b/mysql-test/suite/rpl/t/rpl_sync-slave.opt new file mode 100644 index 00000000000..77809a42c43 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sync-slave.opt @@ -0,0 +1 @@ +--sync-relay-log-info=1 --relay-log-recovery=1 diff --git a/mysql-test/suite/rpl/t/rpl_sync.test b/mysql-test/suite/rpl/t/rpl_sync.test new file mode 100644 index 00000000000..80b6a144187 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sync.test @@ -0,0 +1,148 @@ +######################################################################################## +# This test verifies the options --sync-relay-log-info and --relay-log-recovery by +# crashing the slave in two different situations: +# (case-1) - Corrupt the relay log with changes which were not processed by +# the SQL Thread and crashes it. +# (case-2) - Corrupt the master.info with wrong coordinates and crashes it. +# +# Case 1: +# 1 - Stops the SQL Thread +# 2 - Inserts new records into the master. +# 3 - Corrupts the relay-log.bin* which most likely has such changes. +# 4 - Crashes the slave +# 5 - Verifies if the slave is sync with the master which means that the information +# loss was circumvented by the recovery process. +# +# Case 2: +# 1 - Stops the SQL/IO Threads +# 2 - Inserts new records into the master. +# 3 - Corrupts the master.info with wrong coordinates. +# 4 - Crashes the slave +# 5 - Verifies if the slave is sync with the master which means that the information +# loss was circumvented by the recovery process. +######################################################################################## + +######################################################################################## +# Configuring the environment +######################################################################################## +--echo =====Configuring the enviroment=======; +--source include/master-slave.inc +--source include/not_embedded.inc +--source include/not_valgrind.inc +--source include/have_debug.inc +--source include/have_innodb.inc + +call mtr.add_suppression('Attempting backtrace'); +call mtr.add_suppression("Recovery from master pos .* and file master-bin.000001"); +CREATE TABLE t1(a INT, PRIMARY KEY(a)) engine=innodb; + +insert into t1(a) values(1); +insert into t1(a) values(2); +insert into t1(a) values(3); + +######################################################################################## +# Case 1: Corrupt a relay-log.bin* +######################################################################################## +--echo =====Inserting data on the master but without the SQL Thread being running=======; +sync_slave_with_master; + +connection slave; +let $MYSQLD_SLAVE_DATADIR= `select @@datadir`; +--replace_result $MYSQLD_SLAVE_DATADIR MYSQLD_SLAVE_DATADIR +--copy_file $MYSQLD_SLAVE_DATADIR/master.info $MYSQLD_SLAVE_DATADIR/master.backup +stop slave SQL_THREAD; +source include/wait_for_slave_sql_to_stop.inc; + +connection master; +insert into t1(a) values(4); +insert into t1(a) values(5); +insert into t1(a) values(6); + +--echo =====Removing relay log files and crashing/recoverying the slave=======; +connection slave; +stop slave IO_THREAD; +source include/wait_for_slave_io_to_stop.inc; + +let $file= query_get_value("SHOW SLAVE STATUS", Relay_Log_File, 1); +--replace_result $MYSQLD_SLAVE_DATADIR MYSQLD_SLAVE_DATADIR +--exec echo "failure" > $MYSQLD_SLAVE_DATADIR/$file + +--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +SET SESSION debug="d,crash_before_rotate_relaylog"; +--error 2013 +FLUSH LOGS; + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--echo =====Dumping and comparing tables=======; +start slave; +source include/wait_for_slave_to_start.inc; + +connection master; +sync_slave_with_master; + +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +######################################################################################## +# Case 2: Corrupt a master.info +######################################################################################## +--echo =====Corrupting the master.info=======; +connection slave; +stop slave; +source include/wait_for_slave_to_stop.inc; + +connection master; +FLUSH LOGS; + +insert into t1(a) values(7); +insert into t1(a) values(8); +insert into t1(a) values(9); + +connection slave; +--replace_result $MYSQLD_SLAVE_DATADIR MYSQLD_SLAVE_DATADIR +--exec cat $MYSQLD_SLAVE_DATADIR/master.backup > $MYSQLD_SLAVE_DATADIR/master.info + +let MYSQLD_SLAVE_DATADIR=`select @@datadir`; + +--perl +use strict; +use warnings; +my $src= "$ENV{'MYSQLD_SLAVE_DATADIR'}/master.backup"; +my $dst= "$ENV{'MYSQLD_SLAVE_DATADIR'}/master.info"; +open(FILE, "<", $src) or die; +my @content= ; +close FILE; +open(FILE, ">", $dst) or die; +binmode FILE; +print FILE @content; +close FILE; +EOF + +--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +SET SESSION debug="d,crash_before_rotate_relaylog"; +--error 2013 +FLUSH LOGS; + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--echo =====Dumping and comparing tables=======; +start slave; +source include/wait_for_slave_to_start.inc; + +connection master; +sync_slave_with_master; + +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +######################################################################################## +# Clean up +######################################################################################## +--echo =====Clean up=======; +connection master; +drop table t1; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 669942cc691..435513832d0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1869,10 +1869,12 @@ extern ulong MYSQL_PLUGIN_IMPORT specialflag; #ifdef MYSQL_SERVER extern ulong current_pid; extern ulong expire_logs_days; -extern uint sync_binlog_period, sync_relaylog_period; +extern uint sync_binlog_period, sync_relaylog_period, + sync_relayloginfo_period, sync_masterinfo_period; extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size; extern ulong tc_log_page_waits; extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb; +extern my_bool relay_log_recovery; extern uint test_flags,select_errors,ha_open_options; extern uint protocol_version, mysqld_port, dropping_tables; extern uint delay_key_write_options; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8febc0bb7e5..b8d09fd4e5a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -477,6 +477,7 @@ extern const char *opt_ndb_distribution; extern enum ndb_distribution opt_ndb_distribution_id; #endif my_bool opt_readonly, use_temp_pool, relay_log_purge; +my_bool relay_log_recovery; my_bool opt_sync_frm, opt_allow_suspicious_udfs; my_bool opt_secure_auth= 0; char* opt_secure_file_priv= 0; @@ -553,7 +554,8 @@ ulong max_prepared_stmt_count; ulong prepared_stmt_count=0; ulong thread_id=1L,current_pid; ulong slow_launch_threads = 0; -uint sync_binlog_period= 0, sync_relaylog_period= 0; +uint sync_binlog_period= 0, sync_relaylog_period= 0, + sync_relayloginfo_period= 0, sync_masterinfo_period= 0; ulong expire_logs_days = 0; ulong rpl_recovery_rank=0; const char *log_output_str= "FILE"; @@ -5605,6 +5607,7 @@ enum options_mysqld OPT_QUERY_CACHE_TYPE, OPT_QUERY_CACHE_WLOCK_INVALIDATE, OPT_RECORD_BUFFER, OPT_RECORD_RND_BUFFER, OPT_DIV_PRECINCREMENT, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE, + OPT_RELAY_LOG_RECOVERY, OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME, OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_DEBUGGING, OPT_SORT_BUFFER, OPT_TABLE_OPEN_CACHE, OPT_TABLE_DEF_CACHE, @@ -5669,7 +5672,9 @@ enum options_mysqld OPT_GENERAL_LOG_FILE, OPT_SLOW_QUERY_LOG_FILE, OPT_IGNORE_BUILTIN_INNODB, - OPT_SYNC_RELAY_LOG + OPT_SYNC_RELAY_LOG, + OPT_SYNC_RELAY_LOG_INFO, + OPT_SYNC_MASTER_INFO }; @@ -6889,6 +6894,13 @@ The minimum value for this variable is 4096.", (uchar**) &relay_log_purge, (uchar**) &relay_log_purge, 0, GET_BOOL, NO_ARG, 1, 0, 1, 0, 1, 0}, + {"relay_log_recovery", OPT_RELAY_LOG_RECOVERY, + "Enables automatic relay log recovery right after the database startup, " + "which means that the IO Thread starts re-fetching from the master " + "right after the last transaction processed.", + (uchar**) &relay_log_recovery, + (uchar**) &relay_log_recovery, 0, GET_BOOL, NO_ARG, + 0, 0, 1, 0, 1, 0}, {"relay_log_space_limit", OPT_RELAY_LOG_SPACE_LIMIT, "Maximum space to use for all relay logs.", (uchar**) &relay_log_space_limit, @@ -6930,6 +6942,16 @@ The minimum value for this variable is 4096.", "Use 0 (default) to disable synchronous flushing.", (uchar**) &sync_relaylog_period, (uchar**) &sync_relaylog_period, 0, GET_UINT, REQUIRED_ARG, 0, 0, (longlong) UINT_MAX, 0, 1, 0}, + {"sync-relay-log-info", OPT_SYNC_RELAY_LOG_INFO, + "Synchronously flush relay log info to disk after #th transaction. " + "Use 0 (default) to disable synchronous flushing.", + (uchar**) &sync_relayloginfo_period, (uchar**) &sync_relayloginfo_period, 0, GET_UINT, + REQUIRED_ARG, 0, 0, (longlong) UINT_MAX, 0, 1, 0}, + {"sync-master-info", OPT_SYNC_MASTER_INFO, + "Synchronously flush master info to disk after every #th event. " + "Use 0 (default) to disable synchronous flushing.", + (uchar**) &sync_masterinfo_period, (uchar**) &sync_masterinfo_period, 0, GET_UINT, + REQUIRED_ARG, 0, 0, (longlong) UINT_MAX, 0, 1, 0}, {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.", (uchar**) &opt_sync_frm, (uchar**) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 1bca44ac613..cec2eabdd20 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -27,11 +27,11 @@ int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val); -Master_info::Master_info() +Master_info::Master_info(bool is_slave_recovery) :Slave_reporting_capability("I/O"), ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), inited(0), - abort_slave(0),slave_running(0), - slave_run_id(0) + rli(is_slave_recovery), abort_slave(0), slave_running(0), + slave_run_id(0), sync_counter(0) { host[0] = 0; user[0] = 0; password[0] = 0; ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; @@ -364,11 +364,6 @@ int flush_master_info(Master_info* mi, bool flush_relay_log_cache) IO_CACHE *log_file= mi->rli.relay_log.get_log_file(); if (flush_io_cache(log_file)) DBUG_RETURN(2); - - /* Sync to disk if --sync-relay-log is set */ - if (sync_relaylog_period && - my_sync(log_file->file, MY_WME)) - DBUG_RETURN(2); } /* @@ -398,8 +393,12 @@ int flush_master_info(Master_info* mi, bool flush_relay_log_cache) (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert); err= flush_io_cache(file); - if (sync_relaylog_period && !err) + if (sync_masterinfo_period && !err && + ++(mi->sync_counter) >= sync_masterinfo_period) + { err= my_sync(mi->fd, MYF(MY_WME)); + mi->sync_counter= 0; + } DBUG_RETURN(-err); } diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index 93fb0a98198..c59dffefb7c 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -58,7 +58,7 @@ class Master_info : public Slave_reporting_capability { public: - Master_info(); + Master_info(bool is_slave_recovery); ~Master_info(); /* the variables below are needed because we can change masters on the fly */ @@ -100,6 +100,13 @@ class Master_info : public Slave_reporting_capability */ long clock_diff_with_master; + + /* + Keeps track of the number of events before fsyncing. + The option --sync-master-info determines how many + events should happen before fsyncing. + */ + uint sync_counter; }; void init_master_info_with_options(Master_info* mi); diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 37c0815fb8b..3a12164a1cf 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -28,11 +28,11 @@ int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val); - -Relay_log_info::Relay_log_info() +Relay_log_info::Relay_log_info(bool is_slave_recovery) :Slave_reporting_capability("SQL"), no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id), info_fd(-1), cur_log_fd(-1), relay_log(&sync_relaylog_period), + sync_counter(0), is_relay_log_recovery(is_slave_recovery), save_temporary_tables(0), #if HAVE_purify is_fake(FALSE), @@ -259,7 +259,8 @@ Failed to open the existing relay log info file '%s' (errno %d)", rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos; rli->group_master_log_pos= master_log_pos; - if (init_relay_log_pos(rli, + if (!rli->is_relay_log_recovery && + init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos, 0 /* no data lock*/, @@ -274,6 +275,7 @@ Failed to open the existing relay log info file '%s' (errno %d)", } #ifndef DBUG_OFF + if (!rli->is_relay_log_recovery) { char llbuf1[22], llbuf2[22]; DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s", diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 171778d9675..a5410dd0c79 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -96,6 +96,19 @@ public: LOG_INFO linfo; IO_CACHE cache_buf,*cur_log; + /* + Keeps track of the number of transactions that commits + before fsyncing. The option --sync-relay-log-info determines + how many transactions should commit before fsyncing. + */ + uint sync_counter; + + /* + Identifies when the recovery process is going on. + See sql/slave.cc:init_recovery for further details. + */ + bool is_relay_log_recovery; + /* The following variables are safe to read any time */ /* IO_CACHE of the info file - set only during init or end */ @@ -267,7 +280,7 @@ public: char slave_patternload_file[FN_REFLEN]; size_t slave_patternload_file_size; - Relay_log_info(); + Relay_log_info(bool is_slave_recovery); ~Relay_log_info(); /* diff --git a/sql/set_var.cc b/sql/set_var.cc index f2b5201cf8b..dcc3954ff1e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1534,19 +1534,19 @@ static bool get_unsigned(THD *thd, set_var *var, ulonglong user_max, } -bool sys_var_int_ptr::check(THD *thd, set_var *var) +bool sys_var_uint_ptr::check(THD *thd, set_var *var) { - var->save_result.ulong_value= (ulong) var->value->val_int(); + var->save_result.ulong_value= (ulong) var->value->val_uint(); return 0; } -bool sys_var_int_ptr::update(THD *thd, set_var *var) +bool sys_var_uint_ptr::update(THD *thd, set_var *var) { *value= (uint) var->save_result.ulong_value; return 0; } -void sys_var_int_ptr::set_default(THD *thd, enum_var_type type) +void sys_var_uint_ptr::set_default(THD *thd, enum_var_type type) { *value= (uint) option_limits->def_value; } diff --git a/sql/set_var.h b/sql/set_var.h index 02c87abed88..0202a15836d 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -178,10 +178,10 @@ public: /** Unsigned int system variable class */ -class sys_var_int_ptr :public sys_var +class sys_var_uint_ptr :public sys_var { public: - sys_var_int_ptr(sys_var_chain *chain, const char *name_arg, + sys_var_uint_ptr(sys_var_chain *chain, const char *name_arg, uint *value_ptr_arg, sys_after_update_func after_update_arg= NULL) :sys_var(name_arg, after_update_arg), diff --git a/sql/slave.cc b/sql/slave.cc index fac9ee214c5..5edb47df8b5 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -129,6 +129,7 @@ static bool wait_for_relay_log_space(Relay_log_info* rli); static inline bool io_slave_killed(THD* thd,Master_info* mi); static inline bool sql_slave_killed(THD* thd,Relay_log_info* rli); static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type); +static int init_recovery(Master_info* mi); static void print_slave_skip_errors(void); static int safe_connect(THD* thd, MYSQL* mysql, Master_info* mi); static int safe_reconnect(THD* thd, MYSQL* mysql, Master_info* mi, @@ -220,6 +221,7 @@ void unlock_slave_threads(Master_info* mi) int init_slave() { DBUG_ENTER("init_slave"); + int error= 0; /* This is called when mysqld starts. Before client connections are @@ -231,7 +233,7 @@ int init_slave() TODO: re-write this to interate through the list of files for multi-master */ - active_mi= new Master_info; + active_mi= new Master_info(relay_log_recovery); /* If --slave-skip-errors=... was not used, the string value for the @@ -250,6 +252,7 @@ int init_slave() if (!active_mi) { sql_print_error("Failed to allocate memory for the master info structure"); + error= 1; goto err; } @@ -257,6 +260,13 @@ int init_slave() !master_host, (SLAVE_IO | SLAVE_SQL))) { sql_print_error("Failed to initialize the master info structure"); + error= 1; + goto err; + } + + if (active_mi->rli.is_relay_log_recovery && init_recovery(active_mi)) + { + error= 1; goto err; } @@ -275,18 +285,89 @@ int init_slave() SLAVE_IO | SLAVE_SQL)) { sql_print_error("Failed to create slave threads"); + error= 1; goto err; } } - pthread_mutex_unlock(&LOCK_active_mi); - DBUG_RETURN(0); err: + active_mi->rli.is_relay_log_recovery= FALSE; pthread_mutex_unlock(&LOCK_active_mi); - DBUG_RETURN(1); + DBUG_RETURN(error); } +/* + Updates the master info based on the information stored in the + relay info and ignores relay logs previously retrieved by the IO + thread, which thus starts fetching again based on to the + group_master_log_pos and group_master_log_name. Eventually, the old + relay logs will be purged by the normal purge mechanism. + In the feature, we should improve this routine in order to avoid throwing + away logs that are safely stored in the disk. Note also that this recovery + routine relies on the correctness of the relay-log.info and only tolerates + coordinate problems in master.info. + + In this function, there is no need for a mutex as the caller + (i.e. init_slave) already has one acquired. + + Specifically, the following structures are updated: + + 1 - mi->master_log_pos <-- rli->group_master_log_pos + 2 - mi->master_log_name <-- rli->group_master_log_name + 3 - It moves the relay log to the new relay log file, by + rli->group_relay_log_pos <-- BIN_LOG_HEADER_SIZE; + rli->event_relay_log_pos <-- BIN_LOG_HEADER_SIZE; + rli->group_relay_log_name <-- rli->relay_log.get_log_fname(); + rli->event_relay_log_name <-- rli->relay_log.get_log_fname(); + + If there is an error, it returns (1), otherwise returns (0). + */ +static int init_recovery(Master_info* mi) +{ + const char *errmsg= 0; + DBUG_ENTER("init_recovery"); + + Relay_log_info *rli= &mi->rli; + if (rli->group_master_log_name[0]) + { + mi->master_log_pos= max(BIN_LOG_HEADER_SIZE, + rli->group_master_log_pos); + strmake(mi->master_log_name, rli->group_master_log_name, + sizeof(mi->master_log_name)-1); + + sql_print_warning("Recovery from master pos %ld and file %s.", + (ulong) mi->master_log_pos, mi->master_log_name); + + strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(), + sizeof(rli->group_relay_log_name)-1); + strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(), + sizeof(mi->rli.event_relay_log_name)-1); + + rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE; + + if (init_relay_log_pos(rli, + rli->group_relay_log_name, + rli->group_relay_log_pos, + 0 /*no data lock*/, + &errmsg, 0)) + DBUG_RETURN(1); + + if (flush_master_info(mi, 0)) + { + sql_print_error("Failed to flush master info file"); + DBUG_RETURN(1); + } + if (flush_relay_log_info(rli)) + { + sql_print_error("Failed to flush relay info file"); + DBUG_RETURN(1); + } + } + + DBUG_RETURN(0); +} + /** Convert slave skip errors bitmap into a printable string. */ @@ -3959,7 +4040,14 @@ bool flush_relay_log_info(Relay_log_info* rli) error=1; if (flush_io_cache(file)) error=1; - + if (sync_relayloginfo_period && + !error && + ++(rli->sync_counter) >= sync_relayloginfo_period) + { + if (my_sync(rli->info_fd, MYF(MY_WME))) + error=1; + rli->sync_counter= 0; + } /* Flushing the relay log is done by the slave I/O thread */ DBUG_RETURN(error); } @@ -4366,6 +4454,8 @@ void rotate_relay_log(Master_info* mi) DBUG_ENTER("rotate_relay_log"); Relay_log_info* rli= &mi->rli; + DBUG_EXECUTE_IF("crash_before_rotate_relaylog", abort();); + /* We don't lock rli->run_lock. This would lead to deadlocks. */ pthread_mutex_lock(&mi->run_lock); diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 96e99b57e3c..531242f64d1 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -58,7 +58,7 @@ void mysql_client_binlog_statement(THD* thd) my_bool have_fd_event= TRUE; if (!thd->rli_fake) { - thd->rli_fake= new Relay_log_info; + thd->rli_fake= new Relay_log_info(FALSE); #ifdef HAVE_purify thd->rli_fake->is_fake= TRUE; #endif diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 425d76c8b72..6295dbb0e79 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1769,6 +1769,16 @@ static sys_var_const sys_relay_log_info_file(&vars, "relay_log_info_file", (uchar*) &relay_log_info_file); static sys_var_bool_ptr sys_relay_log_purge(&vars, "relay_log_purge", &relay_log_purge); +static sys_var_bool_ptr sys_relay_log_recovery(&vars, "relay_log_recovery", + &relay_log_recovery); +static sys_var_uint_ptr sys_sync_binlog_period(&vars, "sync_binlog", + &sync_binlog_period); +static sys_var_uint_ptr sys_sync_relaylog_period(&vars, "sync_relay_log", + &sync_relaylog_period); +static sys_var_uint_ptr sys_sync_relayloginfo_period(&vars, "sync_relay_log_info", + &sync_relayloginfo_period); +static sys_var_uint_ptr sys_sync_masterinfo_period(&vars, "sync_master_info", + &sync_masterinfo_period); static sys_var_const sys_relay_log_space_limit(&vars, "relay_log_space_limit", OPT_GLOBAL, SHOW_LONGLONG, @@ -1784,8 +1794,6 @@ static sys_var_const sys_slave_skip_errors(&vars, "slave_skip_errors", (uchar*) slave_skip_error_names); static sys_var_long_ptr sys_slave_trans_retries(&vars, "slave_transaction_retries", &slave_trans_retries); -static sys_var_int_ptr sys_sync_binlog_period(&vars, "sync_binlog", &sync_binlog_period); -static sys_var_int_ptr sys_sync_relaylog_period(&vars, "sync_relay_log", &sync_relaylog_period); static sys_var_slave_skip_counter sys_slave_skip_counter(&vars, "sql_slave_skip_counter"); From 28a7d5042b264136438cb87e76498b8cbd583e7a Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 30 Sep 2009 03:21:00 +0200 Subject: [PATCH 037/274] fix tree name --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index 771201a109b..d771989c69a 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-5.4.5-next-mr" +tree_name = "mysql-next-mr-wtf" From 2bc1930c6c40b964fce9c698a1ca75da3138ad63 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 30 Sep 2009 03:22:57 +0200 Subject: [PATCH 038/274] Windows improvements : manual backport of htttp://lists.mysql.com/commits/50957?f=plain Always use TLS functions instead of __declspec(thread) to access thread local storage variables. The change removes the necessity to recomplile the same source files twice - with USE_TLS for DLLs and without USE_TLS for EXEs. Real benefit of this change is better readability and maintainability of TLS functions within MySQL. There is a performance loss using TlsXXX functions compared to __declspec but the difference is negligible in practice. In a sysbench-like benchmark I ran with with TlsGetValue, pthread_[get|set]_specific was called 600000000 times and took 0.17sec of total 35min CPU time, or 0.008%. --- client/CMakeLists.txt | 18 +++++++++--------- include/my_pthread.h | 24 +++--------------------- libmysql/CMakeLists.txt | 18 +----------------- libmysqld/CMakeLists.txt | 6 ------ libmysqld/examples/CMakeLists.txt | 3 --- mysys/my_thr_init.c | 21 --------------------- mysys/my_winthread.c | 7 ------- tests/CMakeLists.txt | 5 ++--- 8 files changed, 15 insertions(+), 87 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index e96437d40d0..4fadc4e7ae5 100755 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -14,7 +14,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") -# We use the "mysqlclient_notls" library here just as safety, in case +# We use the "mysqlclient" library here just as safety, in case # any of the clients here would go beyond the client API and access the # Thread Local Storage directly. @@ -30,27 +30,27 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/strings) ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc sql_string.cc ../mysys/my_conio.c) -TARGET_LINK_LIBRARIES(mysql mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(mysql mysqlclient wsock32) ADD_EXECUTABLE(mysqltest mysqltest.cc) SET_SOURCE_FILES_PROPERTIES(mysqltest.cc PROPERTIES COMPILE_FLAGS "-DTHREADS") TARGET_LINK_LIBRARIES(mysqltest mysqlclient mysys regex wsock32 dbug) ADD_EXECUTABLE(mysqlcheck mysqlcheck.c) -TARGET_LINK_LIBRARIES(mysqlcheck mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(mysqlcheck mysqlclient wsock32) ADD_EXECUTABLE(mysqldump mysqldump.c ../sql-common/my_user.c ../mysys/mf_getdate.c) -TARGET_LINK_LIBRARIES(mysqldump mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(mysqldump mysqlclient wsock32) ADD_EXECUTABLE(mysqlimport mysqlimport.c) -TARGET_LINK_LIBRARIES(mysqlimport mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(mysqlimport mysqlclient wsock32) ADD_EXECUTABLE(mysql_upgrade mysql_upgrade.c ../mysys/my_getpagesize.c) -TARGET_LINK_LIBRARIES(mysql_upgrade mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(mysql_upgrade mysqlclient wsock32) ADD_DEPENDENCIES(mysql_upgrade GenFixPrivs) ADD_EXECUTABLE(mysqlshow mysqlshow.c) -TARGET_LINK_LIBRARIES(mysqlshow mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(mysqlshow mysqlclient wsock32) ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc ../mysys/mf_tempdir.c @@ -59,10 +59,10 @@ ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc ../mysys/my_bitmap.c ../mysys/my_vle.c ../mysys/base64.c) -TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient wsock32) ADD_EXECUTABLE(mysqladmin mysqladmin.cc) -TARGET_LINK_LIBRARIES(mysqladmin mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(mysqladmin mysqlclient wsock32) ADD_EXECUTABLE(mysqlslap mysqlslap.c) SET_SOURCE_FILES_PROPERTIES(mysqlslap.c PROPERTIES COMPILE_FLAGS "-DTHREADS") diff --git a/include/my_pthread.h b/include/my_pthread.h index 9e2c2111b8e..2928cb60c2d 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -100,7 +100,6 @@ struct timespec { } void win_pthread_init(void); -int win_pthread_setspecific(void *A,void *B,uint length); int win_pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *); int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); @@ -126,33 +125,16 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #define _REENTRANT 1 #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 -/* - Windows has two ways to use thread local storage. The most efficient - is using __declspec(thread), but that does not work properly when - used in a .dll that is loaded at runtime, after program load. So for - libmysql.dll and libmysqld.dll we define USE_TLS in order to use the - TlsXxx() API instead, which works in all cases. -*/ -#ifdef USE_TLS /* For LIBMYSQL.DLL */ + #undef SAFE_MUTEX /* This will cause conflicts */ #define pthread_key(T,V) DWORD V #define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF) #define pthread_key_delete(A) TlsFree(A) +#define my_pthread_setspecific_ptr(T,V) (!TlsSetValue((T),(V))) +#define pthread_setspecific(A,B) (!TlsSetValue((A),(B))) #define pthread_getspecific(A) (TlsGetValue(A)) #define my_pthread_getspecific(T,A) ((T) TlsGetValue(A)) #define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(V)) -#define my_pthread_setspecific_ptr(T,V) (!TlsSetValue((T),(V))) -#define pthread_setspecific(A,B) (!TlsSetValue((A),(B))) -#else -#define pthread_key(T,V) __declspec(thread) T V -#define pthread_key_create(A,B) pthread_dummy(0) -#define pthread_key_delete(A) pthread_dummy(0) -#define pthread_getspecific(A) (&(A)) -#define my_pthread_getspecific(T,A) (&(A)) -#define my_pthread_getspecific_ptr(T,V) (V) -#define my_pthread_setspecific_ptr(T,V) ((T)=(V),0) -#define pthread_setspecific(A,B) win_pthread_setspecific(&(A),(B),sizeof(A)) -#endif /* USE_TLS */ #define pthread_equal(A,B) ((A) == (B)) #define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index b252d94b50e..06c17c80bfe 100755 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -100,29 +100,13 @@ SET(CLIENT_SOURCES ../mysys/array.c ../strings/bchange.c ../strings/bmove.c ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c ../mysys/mf_qsort.c ../mysys/my_getsystime.c ../mysys/my_sync.c ../mysys/my_winerr.c ../mysys/my_winfile.c ${LIB_SOURCES}) -# Need to set USE_TLS for building the DLL, since __declspec(thread) -# approach to thread local storage does not work properly in DLLs. -# -# The static library might be used to form another DLL, as is the case -# with the ODBC driver, so it has to be compiled with USE_TLS as well. -# -# We create a third library without USE_TLS for internal use. We can't -# be sure that some client application part of this build doesn't go -# beond the documented API, and try access the Thread Local Storage. -# The "_notls" means no Tls*() functions used, i.e. "static" TLS. + ADD_LIBRARY(mysqlclient STATIC ${CLIENT_SOURCES}) ADD_DEPENDENCIES(mysqlclient GenError) TARGET_LINK_LIBRARIES(mysqlclient) -ADD_LIBRARY(mysqlclient_notls STATIC ${CLIENT_SOURCES}) -ADD_DEPENDENCIES(mysqlclient_notls GenError) -TARGET_LINK_LIBRARIES(mysqlclient_notls) - ADD_LIBRARY(libmysql SHARED ${CLIENT_SOURCES} dll.c libmysql.def) -IF(WIN32) - SET_TARGET_PROPERTIES(libmysql mysqlclient PROPERTIES COMPILE_FLAGS "-DUSE_TLS") -ENDIF(WIN32) ADD_DEPENDENCIES(libmysql GenError) TARGET_LINK_LIBRARIES(libmysql wsock32) diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index b31082b438a..f180c6e1921 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -16,12 +16,6 @@ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -# Need to set USE_TLS, since __declspec(thread) approach to thread local -# storage does not work properly in DLLs. -IF(WIN32) - ADD_DEFINITIONS(-DUSE_TLS) -ENDIF(WIN32) - ADD_DEFINITIONS(-DMYSQL_SERVER -DEMBEDDED_LIBRARY -DHAVE_DLOPEN) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include diff --git a/libmysqld/examples/CMakeLists.txt b/libmysqld/examples/CMakeLists.txt index 5194836a728..e4b6533f8a2 100644 --- a/libmysqld/examples/CMakeLists.txt +++ b/libmysqld/examples/CMakeLists.txt @@ -20,9 +20,6 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/extra/yassl/include) # Currently does not work with DBUG, there are missing symbols reported. -IF(WIN32) - ADD_DEFINITIONS(-DUSE_TLS) -ENDIF(WIN32) ADD_DEFINITIONS(-DEMBEDDED_LIBRARY) diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 2278c467f32..2c346145cf5 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -23,11 +23,7 @@ #include #ifdef THREAD -#ifdef USE_TLS pthread_key(struct st_my_thread_var*, THR_KEY_mysys); -#else -pthread_key(struct st_my_thread_var, THR_KEY_mysys); -#endif /* USE_TLS */ pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open, THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap, THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time; @@ -258,7 +254,6 @@ my_bool my_thread_init(void) (ulong) pthread_self()); #endif -#if !defined(__WIN__) || defined(USE_TLS) if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys)) { #ifdef EXTRA_DEBUG_THREADS @@ -273,15 +268,6 @@ my_bool my_thread_init(void) goto end; } pthread_setspecific(THR_KEY_mysys,tmp); - -#else /* defined(__WIN__) && !(defined(USE_TLS) */ - /* - Skip initialization if the thread specific variable is already initialized - */ - if (THR_KEY_mysys.id) - goto end; - tmp= &THR_KEY_mysys; -#endif #if defined(__WIN__) && defined(EMBEDDED_LIBRARY) tmp->pthread_self= (pthread_t) getpid(); #else @@ -342,11 +328,7 @@ void my_thread_end(void) pthread_cond_destroy(&tmp->suspend); #endif pthread_mutex_destroy(&tmp->mutex); -#if !defined(__WIN__) || defined(USE_TLS) free(tmp); -#else - tmp->init= 0; -#endif /* Decrement counter for number of running threads. We are using this @@ -360,10 +342,7 @@ void my_thread_end(void) pthread_cond_signal(&THR_COND_threads); pthread_mutex_unlock(&THR_LOCK_threads); } - /* The following free has to be done, even if my_thread_var() is 0 */ -#if !defined(__WIN__) || defined(USE_TLS) pthread_setspecific(THR_KEY_mysys,0); -#endif } struct st_my_thread_var *_my_thread_var(void) diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c index e94369bec32..543e1787fb6 100644 --- a/mysys/my_winthread.c +++ b/mysys/my_winthread.c @@ -129,12 +129,5 @@ void pthread_exit(void *a) _endthread(); } -/* This is neaded to get the macro pthread_setspecific to work */ - -int win_pthread_setspecific(void *a,void *b,uint length) -{ - memcpy(a,b,length); - return 0; -} #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2093fc0da36..9ddfadcda4e 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,7 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# About "mysqlclient_notls", see note in "client/CMakeLists.txt" SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") ADD_DEFINITIONS("-DMYSQL_CLIENT") @@ -21,7 +20,7 @@ ADD_DEFINITIONS("-DMYSQL_CLIENT") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) ADD_EXECUTABLE(mysql_client_test mysql_client_test.c ../mysys/my_memmem.c) -TARGET_LINK_LIBRARIES(mysql_client_test mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(mysql_client_test mysqlclient wsock32) ADD_EXECUTABLE(bug25714 bug25714.c) -TARGET_LINK_LIBRARIES(bug25714 mysqlclient_notls wsock32) +TARGET_LINK_LIBRARIES(bug25714 mysqlclient wsock32) From b73763e0f913a1b3e841cbe91f9d11802cbf054c Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 30 Sep 2009 03:39:37 +0200 Subject: [PATCH 039/274] Backport of the patch http://lists.mysql.com/commits/57725 Vladislav Vaintroub 2008-11-03 Cleanup CMakeLists.txt(s) - remove winsock2 (ws2_32) from TARGET_LINK_LIBRARIES. Every exe or dll linked with mysys needs ws2_32, because mysys uses winsock function WSAStartup in my_init(). However, there is no need to explicitely add ws2_32 to the list of TARGET_LINK_LIBRARIES multiple times. Visual Studio comes with a handy pragma that tells linker to add library. So patch replaces bunch of ws2_32 in CMakeLists with single pragma comment(lib,"ws2_32") in my_init.c Additionally, reference to non-existing "debug" library has been removed from TARGET_LINK_LIBRARIES. The correct name of the library is "dbug". --- client/CMakeLists.txt | 20 ++++++++++---------- extra/CMakeLists.txt | 10 +++++----- libmysql/CMakeLists.txt | 2 +- mysys/my_init.c | 2 ++ scripts/CMakeLists.txt | 2 +- sql/CMakeLists.txt | 5 ++--- sql/udf_example.c | 5 +++++ storage/myisam/CMakeLists.txt | 8 ++++---- tests/CMakeLists.txt | 4 ++-- 9 files changed, 32 insertions(+), 26 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 4fadc4e7ae5..176613e2dc8 100755 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -30,27 +30,27 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/strings) ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc sql_string.cc ../mysys/my_conio.c) -TARGET_LINK_LIBRARIES(mysql mysqlclient wsock32) +TARGET_LINK_LIBRARIES(mysql mysqlclient) ADD_EXECUTABLE(mysqltest mysqltest.cc) SET_SOURCE_FILES_PROPERTIES(mysqltest.cc PROPERTIES COMPILE_FLAGS "-DTHREADS") -TARGET_LINK_LIBRARIES(mysqltest mysqlclient mysys regex wsock32 dbug) +TARGET_LINK_LIBRARIES(mysqltest mysqlclient mysys regex dbug) ADD_EXECUTABLE(mysqlcheck mysqlcheck.c) -TARGET_LINK_LIBRARIES(mysqlcheck mysqlclient wsock32) +TARGET_LINK_LIBRARIES(mysqlcheck mysqlclient) ADD_EXECUTABLE(mysqldump mysqldump.c ../sql-common/my_user.c ../mysys/mf_getdate.c) -TARGET_LINK_LIBRARIES(mysqldump mysqlclient wsock32) +TARGET_LINK_LIBRARIES(mysqldump mysqlclient) ADD_EXECUTABLE(mysqlimport mysqlimport.c) -TARGET_LINK_LIBRARIES(mysqlimport mysqlclient wsock32) +TARGET_LINK_LIBRARIES(mysqlimport mysqlclient) ADD_EXECUTABLE(mysql_upgrade mysql_upgrade.c ../mysys/my_getpagesize.c) -TARGET_LINK_LIBRARIES(mysql_upgrade mysqlclient wsock32) +TARGET_LINK_LIBRARIES(mysql_upgrade mysqlclient) ADD_DEPENDENCIES(mysql_upgrade GenFixPrivs) ADD_EXECUTABLE(mysqlshow mysqlshow.c) -TARGET_LINK_LIBRARIES(mysqlshow mysqlclient wsock32) +TARGET_LINK_LIBRARIES(mysqlshow mysqlclient) ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc ../mysys/mf_tempdir.c @@ -59,14 +59,14 @@ ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc ../mysys/my_bitmap.c ../mysys/my_vle.c ../mysys/base64.c) -TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient wsock32) +TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient) ADD_EXECUTABLE(mysqladmin mysqladmin.cc) -TARGET_LINK_LIBRARIES(mysqladmin mysqlclient wsock32) +TARGET_LINK_LIBRARIES(mysqladmin mysqlclient) ADD_EXECUTABLE(mysqlslap mysqlslap.c) SET_SOURCE_FILES_PROPERTIES(mysqlslap.c PROPERTIES COMPILE_FLAGS "-DTHREADS") -TARGET_LINK_LIBRARIES(mysqlslap mysqlclient mysys zlib wsock32 dbug) +TARGET_LINK_LIBRARIES(mysqlslap mysqlclient mysys zlib dbug) ADD_EXECUTABLE(echo echo.c) diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt index cec0db6a4ae..0d09e676af1 100755 --- a/extra/CMakeLists.txt +++ b/extra/CMakeLists.txt @@ -20,7 +20,7 @@ SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) ADD_EXECUTABLE(comp_err comp_err.c) -TARGET_LINK_LIBRARIES(comp_err debug dbug mysys strings zlib wsock32) +TARGET_LINK_LIBRARIES(comp_err dbug mysys strings zlib) GET_TARGET_PROPERTY(COMP_ERR_EXE comp_err LOCATION) @@ -39,16 +39,16 @@ ADD_CUSTOM_TARGET(GenError DEPENDS ${PROJECT_SOURCE_DIR}/include/mysqld_error.h) ADD_EXECUTABLE(my_print_defaults my_print_defaults.c) -TARGET_LINK_LIBRARIES(my_print_defaults strings mysys debug dbug taocrypt wsock32) +TARGET_LINK_LIBRARIES(my_print_defaults strings mysys dbug taocrypt) ADD_EXECUTABLE(perror perror.c) -TARGET_LINK_LIBRARIES(perror strings mysys debug dbug wsock32) +TARGET_LINK_LIBRARIES(perror strings mysys dbug) ADD_EXECUTABLE(resolveip resolveip.c) -TARGET_LINK_LIBRARIES(resolveip strings mysys debug dbug wsock32) +TARGET_LINK_LIBRARIES(resolveip strings mysys dbug) ADD_EXECUTABLE(replace replace.c) -TARGET_LINK_LIBRARIES(replace strings mysys debug dbug wsock32) +TARGET_LINK_LIBRARIES(replace strings mysys dbug) IF(EMBED_MANIFESTS) MYSQL_EMBED_MANIFEST("myTest" "asInvoker") diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index 06c17c80bfe..29fe4ca33c3 100755 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -108,7 +108,7 @@ TARGET_LINK_LIBRARIES(mysqlclient) ADD_LIBRARY(libmysql SHARED ${CLIENT_SOURCES} dll.c libmysql.def) ADD_DEPENDENCIES(libmysql GenError) -TARGET_LINK_LIBRARIES(libmysql wsock32) +TARGET_LINK_LIBRARIES(libmysql) IF(EMBED_MANIFESTS) MYSQL_EMBED_MANIFEST("myTest" "asInvoker") diff --git a/mysys/my_init.c b/mysys/my_init.c index a60927be693..c4fda599481 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -27,6 +27,8 @@ #ifdef _MSC_VER #include #include +/* WSAStartup needs winsock library*/ +#pragma comment(lib, "ws2_32") #endif my_bool have_tcpip=0; static void my_win_init(void); diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index f0db25be79a..25cdae2b522 100755 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -24,7 +24,7 @@ ADD_CUSTOM_COMMAND(OUTPUT ${PROJECT_SOURCE_DIR}/scripts/mysql_fix_privilege_tabl # Build comp_sql - used for embedding SQL in C or C++ programs ADD_EXECUTABLE(comp_sql comp_sql.c) -TARGET_LINK_LIBRARIES(comp_sql debug dbug mysys strings) +TARGET_LINK_LIBRARIES(comp_sql dbug mysys strings) # Use comp_sql to build mysql_fix_privilege_tables_sql.c GET_TARGET_PROPERTY(COMP_SQL_EXE comp_sql LOCATION) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 592092ba7aa..1b7175a7b82 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -96,7 +96,6 @@ SET_TARGET_PROPERTIES(mysqld PROPERTIES ENABLE_EXPORTS TRUE) SET (MYSQLD_CORE_LIBS mysys zlib dbug strings yassl taocrypt vio regex sql) TARGET_LINK_LIBRARIES(mysqld ${MYSQLD_CORE_LIBS} ${MYSQLD_STATIC_ENGINE_LIBS}) -TARGET_LINK_LIBRARIES(mysqld ws2_32.lib) IF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS) @@ -129,7 +128,7 @@ ADD_CUSTOM_COMMAND( # Gen_lex_hash ADD_EXECUTABLE(gen_lex_hash gen_lex_hash.cc) -TARGET_LINK_LIBRARIES(gen_lex_hash debug dbug mysqlclient wsock32) +TARGET_LINK_LIBRARIES(gen_lex_hash dbug mysqlclient) GET_TARGET_PROPERTY(GEN_LEX_HASH_EXE gen_lex_hash LOCATION) ADD_CUSTOM_COMMAND( OUTPUT ${PROJECT_SOURCE_DIR}/sql/lex_hash.h @@ -152,4 +151,4 @@ SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def) ADD_DEPENDENCIES(udf_example strings GenError) -TARGET_LINK_LIBRARIES(udf_example strings wsock32) +TARGET_LINK_LIBRARIES(udf_example strings) diff --git a/sql/udf_example.c b/sql/udf_example.c index 30d85d95034..1d6a9828594 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -138,6 +138,11 @@ typedef long long longlong; #endif #include #include + +#ifdef _WIN32 +/* inet_aton needs winsock library */ +#pragma comment(lib, "ws2_32") +#endif static pthread_mutex_t LOCK_hostname; diff --git a/storage/myisam/CMakeLists.txt b/storage/myisam/CMakeLists.txt index c05e0046e64..0f070510e5c 100755 --- a/storage/myisam/CMakeLists.txt +++ b/storage/myisam/CMakeLists.txt @@ -34,16 +34,16 @@ MYSQL_STORAGE_ENGINE(MYISAM) IF(NOT SOURCE_SUBLIBS) ADD_EXECUTABLE(myisam_ftdump myisam_ftdump.c) - TARGET_LINK_LIBRARIES(myisam_ftdump myisam mysys debug dbug strings zlib wsock32) + TARGET_LINK_LIBRARIES(myisam_ftdump myisam mysys dbug strings zlib) ADD_EXECUTABLE(myisamchk myisamchk.c) - TARGET_LINK_LIBRARIES(myisamchk myisam mysys debug dbug strings zlib wsock32) + TARGET_LINK_LIBRARIES(myisamchk myisam mysys dbug strings zlib) ADD_EXECUTABLE(myisamlog myisamlog.c) - TARGET_LINK_LIBRARIES(myisamlog myisam mysys debug dbug strings zlib wsock32) + TARGET_LINK_LIBRARIES(myisamlog myisam mysys dbug strings zlib) ADD_EXECUTABLE(myisampack myisampack.c) - TARGET_LINK_LIBRARIES(myisampack myisam mysys debug dbug strings zlib wsock32) + TARGET_LINK_LIBRARIES(myisampack myisam mysys dbug strings zlib) SET_TARGET_PROPERTIES(myisamchk myisampack PROPERTIES LINK_FLAGS "setargv.obj") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9ddfadcda4e..270aaf53c20 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,7 +20,7 @@ ADD_DEFINITIONS("-DMYSQL_CLIENT") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) ADD_EXECUTABLE(mysql_client_test mysql_client_test.c ../mysys/my_memmem.c) -TARGET_LINK_LIBRARIES(mysql_client_test mysqlclient wsock32) +TARGET_LINK_LIBRARIES(mysql_client_test mysqlclient) ADD_EXECUTABLE(bug25714 bug25714.c) -TARGET_LINK_LIBRARIES(bug25714 mysqlclient wsock32) +TARGET_LINK_LIBRARIES(bug25714 mysqlclient) From f02800bd9733efbdc1328f866ad0ef2779939f7c Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 30 Sep 2009 10:09:28 +0500 Subject: [PATCH 040/274] Backporting WL#3759 Optimize identifier conversion in client-server protocol This patch provides performance improvements: - send_fields() when character_set_results = latin1 is now about twice faster for column/table/database names, consisting on ASCII characters. Changes: - Protocol doesn't use "convert" temporary buffer anymore, and converts strings directly to "packet". - General conversion optimization: quick conversion of ASCII strings was added. modified files: include/m_ctype.h - Adding a new flag. - Adding a new function prototype libmysqld/lib_sql.cc - Adding quick conversion method for embedded library: conversion is now done directly to result buffer, without using a temporary buffer. mysys/charset.c - Mark all dynamic ucs2 character sets as non-ASCII - Mark some dymamic 7bit and 8bit charsets as non-ASCII (for example swe7 is not fully ASCII compatible). sql/protocol.cc - Adding quick method to convert a string directly into protocol buffer, without using a temporary buffer. sql/protocol.h - Adding a new method prototype sql/sql_string.cc Optimization for conversion between two ASCII-compatible charsets: - quickly convert ASCII strings, switch to mc_wc->wc_mb method only when a non-ASCII character is met. - copy four ASCII characters at once on i386 strings/conf_to_src.c - Marking non-ASCII character sets with a flag. strings/ctype-extra.c - Regenerating ctype-extra.c by running "conf_to_src". strings/ctype-uca.c - Marking UCS2 character set as non-ASCII. strings/ctype-ucs2.c - Marking UCS2 character set as non-ASCII. strings/ctype.c - A new function to detect if a 7bit or 8bit character set is ascii compatible. --- include/m_ctype.h | 2 ++ libmysqld/lib_sql.cc | 24 ++++++++++++++ mysys/charset.c | 3 ++ sql/protocol.cc | 64 ++++++++++++++++++++++++++++++++++-- sql/protocol.h | 2 ++ sql/sql_string.cc | 68 +++++++++++++++++++++++++++++++++++--- strings/conf_to_src.c | 5 +-- strings/ctype-extra.c | 72 ++-------------------------------------- strings/ctype-uca.c | 76 +++++++++++++++++++++---------------------- strings/ctype-ucs2.c | 4 +-- strings/ctype.c | 20 ++++++++++++ 11 files changed, 222 insertions(+), 118 deletions(-) diff --git a/include/m_ctype.h b/include/m_ctype.h index 451c8db549b..f6503a54935 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -87,6 +87,7 @@ extern MY_UNI_CTYPE my_uni_ctype[256]; #define MY_CS_CSSORT 1024 /* if case sensitive sort order */ #define MY_CS_HIDDEN 2048 /* don't display in SHOW */ #define MY_CS_PUREASCII 4096 /* if a charset is pure ascii */ +#define MY_CS_NONASCII 8192 /* if not ASCII-compatible */ #define MY_CHARSET_UNDEFINED 0 /* Character repertoire flags */ @@ -474,6 +475,7 @@ my_bool my_charset_is_ascii_based(CHARSET_INFO *cs); my_bool my_charset_is_8bit_pure_ascii(CHARSET_INFO *cs); uint my_charset_repertoire(CHARSET_INFO *cs); +my_bool my_charset_is_ascii_compatible(CHARSET_INFO *cs); #define _MY_U 01 /* Upper case */ #define _MY_L 02 /* Lower case */ diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 64822f8fad6..2ac2556d4de 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -1175,3 +1175,27 @@ int vprint_msg_to_log(enum loglevel level __attribute__((unused)), mysql_server_last_errno= CR_UNKNOWN_ERROR; return 0; } + + +bool Protocol::net_store_data(const uchar *from, size_t length, + CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) +{ + uint conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen; + uint dummy_error; + char *field_buf; + if (!thd->mysql) // bootstrap file handling + return false; + + if (!(field_buf= (char*) alloc_root(alloc, conv_length + sizeof(uint) + 1))) + return true; + *next_field= field_buf + sizeof(uint); + length= copy_and_convert(*next_field, conv_length, to_cs, + (const char*) from, length, from_cs, &dummy_error); + *(uint *) field_buf= length; + (*next_field)[length]= 0; + if (next_mysql_field->max_length < length) + next_mysql_field->max_length= length; + ++next_field; + ++next_mysql_field; + return false; +} diff --git a/mysys/charset.c b/mysys/charset.c index b23ab084e90..214ca170757 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -248,6 +248,7 @@ static int add_collation(CHARSET_INFO *cs) { #if defined(HAVE_CHARSET_ucs2) && defined(HAVE_UCA_COLLATIONS) copy_uca_collation(newcs, &my_charset_ucs2_unicode_ci); + newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII; #endif } else if (!strcmp(cs->csname, "utf8")) @@ -280,6 +281,8 @@ static int add_collation(CHARSET_INFO *cs) if (my_charset_is_8bit_pure_ascii(all_charsets[cs->number])) all_charsets[cs->number]->state|= MY_CS_PUREASCII; + if (!my_charset_is_ascii_compatible(cs)) + all_charsets[cs->number]->state|= MY_CS_NONASCII; } } else diff --git a/sql/protocol.cc b/sql/protocol.cc index 54e17ff5c3b..7abc051af68 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -58,6 +58,64 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) } + + +/* + net_store_data() - extended version with character set conversion. + + It is optimized for short strings whose length after + conversion is garanteed to be less than 251, which accupies + exactly one byte to store length. It allows not to use + the "convert" member as a temporary buffer, conversion + is done directly to the "packet" member. + The limit 251 is good enough to optimize send_result_set_metadata() + because column, table, database names fit into this limit. +*/ + +#ifndef EMBEDDED_LIBRARY +bool Protocol::net_store_data(const uchar *from, size_t length, + CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) +{ + uint dummy_errors; + /* Calculate maxumum possible result length */ + uint conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen; + if (conv_length > 250) + { + /* + For strings with conv_length greater than 250 bytes + we don't know how many bytes we will need to store length: one or two, + because we don't know result length until conversion is done. + For example, when converting from utf8 (mbmaxlen=3) to latin1, + conv_length=300 means that the result length can vary between 100 to 300. + length=100 needs one byte, length=300 needs to bytes. + + Thus conversion directly to "packet" is not worthy. + Let's use "convert" as a temporary buffer. + */ + return (convert->copy((const char*) from, length, from_cs, + to_cs, &dummy_errors) || + net_store_data((const uchar*) convert->ptr(), convert->length())); + } + + ulong packet_length= packet->length(); + ulong new_length= packet_length + conv_length + 1; + + if (new_length > packet->alloced_length() && packet->realloc(new_length)) + return 1; + + char *length_pos= (char*) packet->ptr() + packet_length; + char *to= length_pos + 1; + + to+= copy_and_convert(to, conv_length, to_cs, + (const char*) from, length, from_cs, &dummy_errors); + + net_store_length((uchar*) length_pos, to - length_pos - 1); + packet->length((uint) (to - packet->ptr())); + return 0; +} +#endif + + /** Send a error string to client. @@ -827,10 +885,10 @@ bool Protocol::store_string_aux(const char *from, size_t length, fromcs != &my_charset_bin && tocs != &my_charset_bin) { - uint dummy_errors; - return (convert->copy(from, length, fromcs, tocs, &dummy_errors) || - net_store_data((uchar*) convert->ptr(), convert->length())); + /* Store with conversion */ + return net_store_data((uchar*) from, length, fromcs, tocs); } + /* Store without conversion */ return net_store_data((uchar*) from, length); } diff --git a/sql/protocol.h b/sql/protocol.h index 1e584295028..3b6a3bdb863 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -43,6 +43,8 @@ protected: MYSQL_FIELD *next_mysql_field; MEM_ROOT *alloc; #endif + bool net_store_data(const uchar *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); bool store_string_aux(const char *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); public: diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 7c9793b273b..593450cacd5 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -794,10 +794,11 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length) */ -uint32 -copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, - const char *from, uint32 from_length, CHARSET_INFO *from_cs, - uint *errors) +static uint32 +copy_and_convert_extended(char *to, uint32 to_length, CHARSET_INFO *to_cs, + const char *from, uint32 from_length, + CHARSET_INFO *from_cs, + uint *errors) { int cnvres; my_wc_t wc; @@ -849,6 +850,65 @@ outp: } +/* + Optimized for quick copying of ASCII characters in the range 0x00..0x7F. +*/ +uint32 +copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, + const char *from, uint32 from_length, CHARSET_INFO *from_cs, + uint *errors) +{ + /* + If any of the character sets is not ASCII compatible, + immediately switch to slow mb_wc->wc_mb method. + */ + if ((to_cs->state | from_cs->state) & MY_CS_NONASCII) + return copy_and_convert_extended(to, to_length, to_cs, + from, from_length, from_cs, errors); + + uint32 length= min(to_length, from_length), length2= length; + +#if defined(__i386__) + /* + Special loop for i386, it allows to refer to a + non-aligned memory block as UINT32, which makes + it possible to copy four bytes at once. This + gives about 10% performance improvement comparing + to byte-by-byte loop. + */ + for ( ; length >= 4; length-= 4, from+= 4, to+= 4) + { + if ((*(uint32*)from) & 0x80808080) + break; + *((uint32*) to)= *((const uint32*) from); + } +#endif + + for (; ; *to++= *from++, length--) + { + if (!length) + { + *errors= 0; + return length2; + } + if (*((unsigned char*) from) > 0x7F) /* A non-ASCII character */ + { + uint32 copied_length= length2 - length; + to_length-= copied_length; + from_length-= copied_length; + return copied_length + copy_and_convert_extended(to, to_length, + to_cs, + from, from_length, + from_cs, + errors); + } + } + + DBUG_ASSERT(FALSE); // Should never get to here + return 0; // Make compiler happy +} + + /** Copy string with HEX-encoding of "bad" characters. diff --git a/strings/conf_to_src.c b/strings/conf_to_src.c index 7e742050aa8..9f1ed9b2441 100644 --- a/strings/conf_to_src.c +++ b/strings/conf_to_src.c @@ -184,11 +184,12 @@ void dispcset(FILE *f,CHARSET_INFO *cs) { fprintf(f,"{\n"); fprintf(f," %d,%d,%d,\n",cs->number,0,0); - fprintf(f," MY_CS_COMPILED%s%s%s%s,\n", + fprintf(f," MY_CS_COMPILED%s%s%s%s%s,\n", cs->state & MY_CS_BINSORT ? "|MY_CS_BINSORT" : "", cs->state & MY_CS_PRIMARY ? "|MY_CS_PRIMARY" : "", is_case_sensitive(cs) ? "|MY_CS_CSSORT" : "", - my_charset_is_8bit_pure_ascii(cs) ? "|MY_CS_PUREASCII" : ""); + my_charset_is_8bit_pure_ascii(cs) ? "|MY_CS_PUREASCII" : "", + !my_charset_is_ascii_compatible(cs) ? "|MY_CS_NONASCII": ""); if (cs->name) { diff --git a/strings/ctype-extra.c b/strings/ctype-extra.c index 75244e40435..ba12f3f4267 100644 --- a/strings/ctype-extra.c +++ b/strings/ctype-extra.c @@ -6,7 +6,7 @@ ./conf_to_src ../sql/share/charsets/ > FILE */ -/* Copyright (C) 2000-2007 MySQL AB +/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. 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 @@ -6804,7 +6804,7 @@ CHARSET_INFO compiled_charsets[] = { #ifdef HAVE_CHARSET_swe7 { 10,0,0, - MY_CS_COMPILED|MY_CS_PRIMARY, + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_NONASCII, "swe7", /* cset name */ "swe7_swedish_ci", /* coll name */ "", /* comment */ @@ -8454,7 +8454,7 @@ CHARSET_INFO compiled_charsets[] = { #ifdef HAVE_CHARSET_swe7 { 82,0,0, - MY_CS_COMPILED|MY_CS_BINSORT, + MY_CS_COMPILED|MY_CS_BINSORT|MY_CS_NONASCII, "swe7", /* cset name */ "swe7_bin", /* coll name */ "", /* comment */ @@ -8550,72 +8550,6 @@ CHARSET_INFO compiled_charsets[] = { } , #endif -#ifdef HAVE_CHARSET_geostd8 -{ - 92,0,0, - MY_CS_COMPILED|MY_CS_PRIMARY, - "geostd8", /* cset name */ - "geostd8_general_ci", /* coll name */ - "", /* comment */ - NULL, /* tailoring */ - ctype_geostd8_general_ci, /* ctype */ - to_lower_geostd8_general_ci, /* lower */ - to_upper_geostd8_general_ci, /* upper */ - sort_order_geostd8_general_ci, /* sort_order */ - NULL, /* contractions */ - NULL, /* sort_order_big*/ - to_uni_geostd8_general_ci, /* to_uni */ - NULL, /* from_uni */ - my_unicase_default, /* caseinfo */ - NULL, /* state map */ - NULL, /* ident map */ - 1, /* strxfrm_multiply*/ - 1, /* caseup_multiply*/ - 1, /* casedn_multiply*/ - 1, /* mbminlen */ - 1, /* mbmaxlen */ - 0, /* min_sort_char */ - 255, /* max_sort_char */ - ' ', /* pad_char */ - 0, /* escape_with_backslash_is_dangerous */ - &my_charset_8bit_handler, - &my_collation_8bit_simple_ci_handler, -} -, -#endif -#ifdef HAVE_CHARSET_geostd8 -{ - 93,0,0, - MY_CS_COMPILED|MY_CS_BINSORT, - "geostd8", /* cset name */ - "geostd8_bin", /* coll name */ - "", /* comment */ - NULL, /* tailoring */ - ctype_geostd8_bin, /* ctype */ - to_lower_geostd8_bin, /* lower */ - to_upper_geostd8_bin, /* upper */ - NULL, /* sort_order */ - NULL, /* contractions */ - NULL, /* sort_order_big*/ - to_uni_geostd8_bin, /* to_uni */ - NULL, /* from_uni */ - my_unicase_default, /* caseinfo */ - NULL, /* state map */ - NULL, /* ident map */ - 1, /* strxfrm_multiply*/ - 1, /* caseup_multiply*/ - 1, /* casedn_multiply*/ - 1, /* mbminlen */ - 1, /* mbmaxlen */ - 0, /* min_sort_char */ - 255, /* max_sort_char */ - ' ', /* pad_char */ - 0, /* escape_with_backslash_is_dangerous */ - &my_charset_8bit_handler, - &my_collation_8bit_bin_handler, -} -, -#endif #ifdef HAVE_CHARSET_latin1 { 94,0,0, diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 2ea48ddab2f..566cc58ab0a 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -8087,7 +8087,7 @@ MY_COLLATION_HANDLER my_collation_ucs2_uca_handler = CHARSET_INFO my_charset_ucs2_unicode_ci= { 128,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_unicode_ci", /* name */ "", /* comment */ @@ -8119,7 +8119,7 @@ CHARSET_INFO my_charset_ucs2_unicode_ci= CHARSET_INFO my_charset_ucs2_icelandic_uca_ci= { 129,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_icelandic_ci",/* name */ "", /* comment */ @@ -8151,7 +8151,7 @@ CHARSET_INFO my_charset_ucs2_icelandic_uca_ci= CHARSET_INFO my_charset_ucs2_latvian_uca_ci= { 130,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_latvian_ci", /* name */ "", /* comment */ @@ -8183,7 +8183,7 @@ CHARSET_INFO my_charset_ucs2_latvian_uca_ci= CHARSET_INFO my_charset_ucs2_romanian_uca_ci= { 131,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_romanian_ci", /* name */ "", /* comment */ @@ -8215,7 +8215,7 @@ CHARSET_INFO my_charset_ucs2_romanian_uca_ci= CHARSET_INFO my_charset_ucs2_slovenian_uca_ci= { 132,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_slovenian_ci",/* name */ "", /* comment */ @@ -8247,7 +8247,7 @@ CHARSET_INFO my_charset_ucs2_slovenian_uca_ci= CHARSET_INFO my_charset_ucs2_polish_uca_ci= { 133,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_polish_ci", /* name */ "", /* comment */ @@ -8279,7 +8279,7 @@ CHARSET_INFO my_charset_ucs2_polish_uca_ci= CHARSET_INFO my_charset_ucs2_estonian_uca_ci= { 134,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_estonian_ci", /* name */ "", /* comment */ @@ -8311,7 +8311,7 @@ CHARSET_INFO my_charset_ucs2_estonian_uca_ci= CHARSET_INFO my_charset_ucs2_spanish_uca_ci= { 135,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_spanish_ci", /* name */ "", /* comment */ @@ -8343,7 +8343,7 @@ CHARSET_INFO my_charset_ucs2_spanish_uca_ci= CHARSET_INFO my_charset_ucs2_swedish_uca_ci= { 136,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_swedish_ci", /* name */ "", /* comment */ @@ -8375,7 +8375,7 @@ CHARSET_INFO my_charset_ucs2_swedish_uca_ci= CHARSET_INFO my_charset_ucs2_turkish_uca_ci= { 137,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_turkish_ci", /* name */ "", /* comment */ @@ -8407,7 +8407,7 @@ CHARSET_INFO my_charset_ucs2_turkish_uca_ci= CHARSET_INFO my_charset_ucs2_czech_uca_ci= { 138,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_czech_ci", /* name */ "", /* comment */ @@ -8440,7 +8440,7 @@ CHARSET_INFO my_charset_ucs2_czech_uca_ci= CHARSET_INFO my_charset_ucs2_danish_uca_ci= { 139,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_danish_ci", /* name */ "", /* comment */ @@ -8472,7 +8472,7 @@ CHARSET_INFO my_charset_ucs2_danish_uca_ci= CHARSET_INFO my_charset_ucs2_lithuanian_uca_ci= { 140,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_lithuanian_ci",/* name */ "", /* comment */ @@ -8504,7 +8504,7 @@ CHARSET_INFO my_charset_ucs2_lithuanian_uca_ci= CHARSET_INFO my_charset_ucs2_slovak_uca_ci= { 141,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_slovak_ci", /* name */ "", /* comment */ @@ -8536,7 +8536,7 @@ CHARSET_INFO my_charset_ucs2_slovak_uca_ci= CHARSET_INFO my_charset_ucs2_spanish2_uca_ci= { 142,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_spanish2_ci", /* name */ "", /* comment */ @@ -8569,7 +8569,7 @@ CHARSET_INFO my_charset_ucs2_spanish2_uca_ci= CHARSET_INFO my_charset_ucs2_roman_uca_ci= { 143,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_roman_ci", /* name */ "", /* comment */ @@ -8602,7 +8602,7 @@ CHARSET_INFO my_charset_ucs2_roman_uca_ci= CHARSET_INFO my_charset_ucs2_persian_uca_ci= { 144,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_persian_ci", /* name */ "", /* comment */ @@ -8635,7 +8635,7 @@ CHARSET_INFO my_charset_ucs2_persian_uca_ci= CHARSET_INFO my_charset_ucs2_esperanto_uca_ci= { 145,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_esperanto_ci",/* name */ "", /* comment */ @@ -8668,7 +8668,7 @@ CHARSET_INFO my_charset_ucs2_esperanto_uca_ci= CHARSET_INFO my_charset_ucs2_hungarian_uca_ci= { 146,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_hungarian_ci",/* name */ "", /* comment */ @@ -8748,7 +8748,7 @@ extern MY_CHARSET_HANDLER my_charset_utf8_handler; CHARSET_INFO my_charset_utf8_unicode_ci= { 192,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_unicode_ci", /* name */ "", /* comment */ @@ -8781,7 +8781,7 @@ CHARSET_INFO my_charset_utf8_unicode_ci= CHARSET_INFO my_charset_utf8_icelandic_uca_ci= { 193,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_icelandic_ci",/* name */ "", /* comment */ @@ -8813,7 +8813,7 @@ CHARSET_INFO my_charset_utf8_icelandic_uca_ci= CHARSET_INFO my_charset_utf8_latvian_uca_ci= { 194,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_latvian_ci", /* name */ "", /* comment */ @@ -8845,7 +8845,7 @@ CHARSET_INFO my_charset_utf8_latvian_uca_ci= CHARSET_INFO my_charset_utf8_romanian_uca_ci= { 195,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_romanian_ci", /* name */ "", /* comment */ @@ -8877,7 +8877,7 @@ CHARSET_INFO my_charset_utf8_romanian_uca_ci= CHARSET_INFO my_charset_utf8_slovenian_uca_ci= { 196,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_slovenian_ci",/* name */ "", /* comment */ @@ -8909,7 +8909,7 @@ CHARSET_INFO my_charset_utf8_slovenian_uca_ci= CHARSET_INFO my_charset_utf8_polish_uca_ci= { 197,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_polish_ci", /* name */ "", /* comment */ @@ -8941,7 +8941,7 @@ CHARSET_INFO my_charset_utf8_polish_uca_ci= CHARSET_INFO my_charset_utf8_estonian_uca_ci= { 198,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_estonian_ci", /* name */ "", /* comment */ @@ -8973,7 +8973,7 @@ CHARSET_INFO my_charset_utf8_estonian_uca_ci= CHARSET_INFO my_charset_utf8_spanish_uca_ci= { 199,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_spanish_ci", /* name */ "", /* comment */ @@ -9005,7 +9005,7 @@ CHARSET_INFO my_charset_utf8_spanish_uca_ci= CHARSET_INFO my_charset_utf8_swedish_uca_ci= { 200,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_swedish_ci", /* name */ "", /* comment */ @@ -9037,7 +9037,7 @@ CHARSET_INFO my_charset_utf8_swedish_uca_ci= CHARSET_INFO my_charset_utf8_turkish_uca_ci= { 201,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_turkish_ci", /* name */ "", /* comment */ @@ -9069,7 +9069,7 @@ CHARSET_INFO my_charset_utf8_turkish_uca_ci= CHARSET_INFO my_charset_utf8_czech_uca_ci= { 202,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_czech_ci", /* name */ "", /* comment */ @@ -9102,7 +9102,7 @@ CHARSET_INFO my_charset_utf8_czech_uca_ci= CHARSET_INFO my_charset_utf8_danish_uca_ci= { 203,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_danish_ci", /* name */ "", /* comment */ @@ -9134,7 +9134,7 @@ CHARSET_INFO my_charset_utf8_danish_uca_ci= CHARSET_INFO my_charset_utf8_lithuanian_uca_ci= { 204,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_lithuanian_ci",/* name */ "", /* comment */ @@ -9166,7 +9166,7 @@ CHARSET_INFO my_charset_utf8_lithuanian_uca_ci= CHARSET_INFO my_charset_utf8_slovak_uca_ci= { 205,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_slovak_ci", /* name */ "", /* comment */ @@ -9198,7 +9198,7 @@ CHARSET_INFO my_charset_utf8_slovak_uca_ci= CHARSET_INFO my_charset_utf8_spanish2_uca_ci= { 206,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_spanish2_ci", /* name */ "", /* comment */ @@ -9230,7 +9230,7 @@ CHARSET_INFO my_charset_utf8_spanish2_uca_ci= CHARSET_INFO my_charset_utf8_roman_uca_ci= { 207,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_roman_ci", /* name */ "", /* comment */ @@ -9262,7 +9262,7 @@ CHARSET_INFO my_charset_utf8_roman_uca_ci= CHARSET_INFO my_charset_utf8_persian_uca_ci= { 208,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_persian_ci", /* name */ "", /* comment */ @@ -9294,7 +9294,7 @@ CHARSET_INFO my_charset_utf8_persian_uca_ci= CHARSET_INFO my_charset_utf8_esperanto_uca_ci= { 209,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_esperanto_ci",/* name */ "", /* comment */ @@ -9326,7 +9326,7 @@ CHARSET_INFO my_charset_utf8_esperanto_uca_ci= CHARSET_INFO my_charset_utf8_hungarian_uca_ci= { 210,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "utf8", /* cs name */ "utf8_hungarian_ci",/* name */ "", /* comment */ diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index a1c691a462b..f030c08523c 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1712,7 +1712,7 @@ MY_CHARSET_HANDLER my_charset_ucs2_handler= CHARSET_INFO my_charset_ucs2_general_ci= { 35,0,0, /* number */ - MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_general_ci", /* name */ "", /* comment */ @@ -1744,7 +1744,7 @@ CHARSET_INFO my_charset_ucs2_general_ci= CHARSET_INFO my_charset_ucs2_bin= { 90,0,0, /* number */ - MY_CS_COMPILED|MY_CS_BINSORT|MY_CS_UNICODE, + MY_CS_COMPILED|MY_CS_BINSORT|MY_CS_UNICODE|MY_CS_NONASCII, "ucs2", /* cs name */ "ucs2_bin", /* name */ "", /* comment */ diff --git a/strings/ctype.c b/strings/ctype.c index 17ad1256e74..75d76aceea3 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -405,3 +405,23 @@ my_charset_is_8bit_pure_ascii(CHARSET_INFO *cs) } return 1; } + + +/* + Shared function between conf_to_src and mysys. + Check if a 8bit character set is compatible with + ascii on the range 0x00..0x7F. +*/ +my_bool +my_charset_is_ascii_compatible(CHARSET_INFO *cs) +{ + uint i; + if (!cs->tab_to_uni) + return 1; + for (i= 0; i < 128; i++) + { + if (cs->tab_to_uni[i] != i) + return 0; + } + return 1; +} From 6799db25041d6feb4deb131fc1f8a4d7359748db Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Wed, 30 Sep 2009 16:09:31 +0800 Subject: [PATCH 041/274] Back porting the test case for semi-sync --- mysql-test/include/have_semisync_plugin.inc | 15 + mysql-test/suite/rpl/r/rpl_semi_sync.result | 398 ++++++++++++++ .../suite/rpl/t/rpl_semi_sync-master.opt | 1 + .../suite/rpl/t/rpl_semi_sync-slave.opt | 1 + mysql-test/suite/rpl/t/rpl_semi_sync.test | 517 ++++++++++++++++++ 5 files changed, 932 insertions(+) create mode 100644 mysql-test/include/have_semisync_plugin.inc create mode 100644 mysql-test/suite/rpl/r/rpl_semi_sync.result create mode 100644 mysql-test/suite/rpl/t/rpl_semi_sync-master.opt create mode 100644 mysql-test/suite/rpl/t/rpl_semi_sync-slave.opt create mode 100644 mysql-test/suite/rpl/t/rpl_semi_sync.test diff --git a/mysql-test/include/have_semisync_plugin.inc b/mysql-test/include/have_semisync_plugin.inc new file mode 100644 index 00000000000..38e2fcd6115 --- /dev/null +++ b/mysql-test/include/have_semisync_plugin.inc @@ -0,0 +1,15 @@ +# +# Check if dynamic loading is supported +# +--require r/have_dynamic_loading.require +disable_query_log; +show variables like 'have_dynamic_loading'; +enable_query_log; + +# +# Check if the variable SEMISYNC_MASTER_PLUGIN is set +# +if (`select LENGTH('$SEMISYNC_MASTER_PLUGIN') = 0`) +{ + skip Need semisync plugins; +} diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync.result b/mysql-test/suite/rpl/r/rpl_semi_sync.result new file mode 100644 index 00000000000..d6f2a3aceff --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync.result @@ -0,0 +1,398 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +# +# Uninstall semi-sync plugins on master and slave +# +include/stop_slave.inc +reset slave; +UNINSTALL PLUGIN rpl_semi_sync_slave; +UNINSTALL PLUGIN rpl_semi_sync_master; +reset master; +set sql_log_bin=0; +UNINSTALL PLUGIN rpl_semi_sync_slave; +UNINSTALL PLUGIN rpl_semi_sync_master; +set sql_log_bin=1; +# +# Main test of semi-sync replication start here +# +[ on master ] +[ default state of semi-sync on master should be OFF ] +show variables like 'rpl_semi_sync_master_enabled'; +Variable_name Value +rpl_semi_sync_master_enabled OFF +[ enable semi-sync on master ] +set global rpl_semi_sync_master_enabled = 1; +show variables like 'rpl_semi_sync_master_enabled'; +Variable_name Value +rpl_semi_sync_master_enabled ON +[ status of semi-sync on master should be OFF without any semi-sync slaves ] +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 0 +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status OFF +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 0 +# +# BUG#45672 Semisync repl: ActiveTranx:insert_tranx_node: transaction node allocation failed +# BUG#45673 Semisynch reports correct operation even if no slave is connected +# +[ status of semi-sync on master should be OFF ] +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 0 +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status OFF +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 0 +# +# INSTALL PLUGIN semi-sync on slave +# +[ on slave ] +[ default state of semi-sync on slave should be OFF ] +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled OFF +[ enable semi-sync on slave ] +set global rpl_semi_sync_slave_enabled = 1; +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled ON +include/start_slave.inc +[ on master ] +[ initial master state after the semi-sync slave connected ] +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 1 +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 0 +create table t1(n int) engine = ENGINE_TYPE; +[ master state after CREATE TABLE statement ] +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 1 +[ insert records to table ] +[ master status after inserts ] +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 301 +[ on slave ] +[ slave status after replicated inserts ] +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status ON +select count(distinct n) from t1; +count(distinct n) +300 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +300 +include/stop_slave.inc +[ on master ] +[ master status should be ON ] +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 301 +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 1 +[ semi-sync replication of these transactions will fail ] +insert into t1 values (500); +delete from t1 where n < 500; +insert into t1 values (100); +[ master status should be OFF ] +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status OFF +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 3 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 301 +[ on slave ] +[ slave status should be OFF ] +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status OFF +include/start_slave.inc +[ slave status should be ON ] +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status ON +select count(distinct n) from t1; +count(distinct n) +2 +select min(n) from t1; +min(n) +100 +select max(n) from t1; +max(n) +500 +[ on master ] +[ do something to activate semi-sync ] +drop table t1; +[ master status should be ON again ] +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 3 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 302 +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 1 +[ on slave ] +include/stop_slave.inc +[ on master ] +show master logs; +Log_name master-bin.000001 +File_size # +show variables like 'rpl_semi_sync_master_enabled'; +Variable_name Value +rpl_semi_sync_master_enabled ON +[ disable semi-sync on the fly ] +set global rpl_semi_sync_master_enabled=0; +show variables like 'rpl_semi_sync_master_enabled'; +Variable_name Value +rpl_semi_sync_master_enabled OFF +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status OFF +[ enable semi-sync on the fly ] +set global rpl_semi_sync_master_enabled=1; +show variables like 'rpl_semi_sync_master_enabled'; +Variable_name Value +rpl_semi_sync_master_enabled ON +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +[ on slave ] +include/start_slave.inc +[ on master ] +create table t1 (a int) engine = ENGINE_TYPE; +drop table t1; +show status like 'Rpl_relay%'; +Variable_name Value +[ test reset master ] +[ on master] +reset master; +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 0 +[ on slave ] +include/stop_slave.inc +reset slave; +include/start_slave.inc +[ on master ] +create table t1 (a int) engine = ENGINE_TYPE; +insert into t1 values (1); +insert into t1 values (2), (3); +[ on slave ] +select * from t1; +a +1 +2 +3 +[ on master ] +[ master semi-sync status should be ON ] +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 3 +# +# Start semi-sync replication without SUPER privilege +# +include/stop_slave.inc +reset slave; +[ on master ] +reset master; +set sql_log_bin=0; +grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl'; +flush privileges; +set sql_log_bin=1; +[ on slave ] +grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl'; +flush privileges; +change master to master_user='rpl',master_password='rpl'; +include/start_slave.inc +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status ON +[ on master ] +[ master semi-sync should be ON ] +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 1 +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 0 +insert into t1 values (4); +insert into t1 values (5); +[ master semi-sync should be ON ] +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 1 +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status ON +show status like 'Rpl_semi_sync_master_no_tx'; +Variable_name Value +Rpl_semi_sync_master_no_tx 0 +show status like 'Rpl_semi_sync_master_yes_tx'; +Variable_name Value +Rpl_semi_sync_master_yes_tx 2 +# +# Test semi-sync slave connect to non-semi-sync master +# +[ on slave ] +include/stop_slave.inc +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status OFF +[ on master ] +[ Semi-sync status on master should be ON ] +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 0 +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status OFF +set global rpl_semi_sync_master_enabled= 0; +[ on slave ] +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled ON +include/start_slave.inc +[ on master ] +insert into t1 values (8); +[ master semi-sync clients should be 0, status should be OFF ] +show status like 'Rpl_semi_sync_master_clients'; +Variable_name Value +Rpl_semi_sync_master_clients 0 +show status like 'Rpl_semi_sync_master_status'; +Variable_name Value +Rpl_semi_sync_master_status OFF +[ on slave ] +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status OFF +include/stop_slave.inc +[ on master ] +set sql_log_bin=0; +UNINSTALL PLUGIN rpl_semi_sync_master; +set sql_log_bin=1; +SHOW VARIABLES LIKE 'rpl_semi_sync_master_enabled'; +Variable_name Value +[ on slave ] +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled ON +include/start_slave.inc +[ on master ] +insert into t1 values (10); +[ on slave ] +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status OFF +# +# Test non-semi-sync slave connect to semi-sync master +# +set sql_log_bin=0; +INSTALL PLUGIN rpl_semi_sync_master SONAME 'libsemisync_master.so'; +set global rpl_semi_sync_master_timeout= 5000; +/* 5s */ +set sql_log_bin=1; +set global rpl_semi_sync_master_enabled= 1; +[ on slave ] +include/stop_slave.inc +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status OFF +[ uninstall semi-sync slave plugin ] +UNINSTALL PLUGIN rpl_semi_sync_slave; +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +Variable_name Value +include/start_slave.inc +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +Variable_name Value +include/stop_slave.inc +[ reinstall semi-sync slave plugin and disable semi-sync ] +INSTALL PLUGIN rpl_semi_sync_slave SONAME 'libsemisync_slave.so'; +set global rpl_semi_sync_slave_enabled= 0; +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled OFF +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status OFF +include/start_slave.inc +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status OFF +# +# Clean up +# +include/stop_slave.inc +UNINSTALL PLUGIN rpl_semi_sync_slave; +UNINSTALL PLUGIN rpl_semi_sync_master; +include/start_slave.inc +drop table t1; +drop user rpl@127.0.0.1; +flush privileges; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync-master.opt b/mysql-test/suite/rpl/t/rpl_semi_sync-master.opt new file mode 100644 index 00000000000..58029d28ace --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync-master.opt @@ -0,0 +1 @@ +$SEMISYNC_PLUGIN_OPT diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync-slave.opt b/mysql-test/suite/rpl/t/rpl_semi_sync-slave.opt new file mode 100644 index 00000000000..58029d28ace --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync-slave.opt @@ -0,0 +1 @@ +$SEMISYNC_PLUGIN_OPT diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync.test b/mysql-test/suite/rpl/t/rpl_semi_sync.test new file mode 100644 index 00000000000..9798ffdb642 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync.test @@ -0,0 +1,517 @@ +source include/have_semisync_plugin.inc; +source include/not_embedded.inc; +source include/not_windows.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +let $engine_type= InnoDB; +#let $engine_type= MyISAM; + +# Suppress warnings that might be generated during the test +disable_query_log; +connection master; +call mtr.add_suppression("Timeout waiting for reply of binlog"); +connection slave; +call mtr.add_suppression("Master server does not support"); +# These will be removed after fix bug#45852 +call mtr.add_suppression("Set 'rpl_semi_sync_master_reply_log_file_pos' on master failed"); +call mtr.add_suppression("Slave I/O: Fatal error: Failed to run 'after_queue_event' hook, Error_code: 1593"); +enable_query_log; + +--echo # +--echo # Uninstall semi-sync plugins on master and slave +--echo # +connection slave; +disable_query_log; +source include/stop_slave.inc; +reset slave; +disable_warnings; +error 0,1305; +UNINSTALL PLUGIN rpl_semi_sync_slave; +error 0,1305; +UNINSTALL PLUGIN rpl_semi_sync_master; +enable_warnings; + +connection master; +reset master; +set sql_log_bin=0; +disable_warnings; +error 0,1305; +UNINSTALL PLUGIN rpl_semi_sync_slave; +error 0,1305; +UNINSTALL PLUGIN rpl_semi_sync_master; +enable_warnings; +set sql_log_bin=1; +enable_query_log; + +--echo # +--echo # Main test of semi-sync replication start here +--echo # + +connection master; +echo [ on master ]; + +disable_query_log; +let $value = query_get_value(show variables like 'rpl_semi_sync_master_enabled', Value, 1); +if (`select '$value' = 'No such row'`) +{ + set sql_log_bin=0; + INSTALL PLUGIN rpl_semi_sync_master SONAME 'libsemisync_master.so'; + set global rpl_semi_sync_master_timeout= 5000; /* 5s */ + set sql_log_bin=1; +} +enable_query_log; + +echo [ default state of semi-sync on master should be OFF ]; +show variables like 'rpl_semi_sync_master_enabled'; + +echo [ enable semi-sync on master ]; +set global rpl_semi_sync_master_enabled = 1; +show variables like 'rpl_semi_sync_master_enabled'; + +echo [ status of semi-sync on master should be OFF without any semi-sync slaves ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +--echo # +--echo # BUG#45672 Semisync repl: ActiveTranx:insert_tranx_node: transaction node allocation failed +--echo # BUG#45673 Semisynch reports correct operation even if no slave is connected +--echo # + +# BUG#45672 When semi-sync is enabled on master, it would allocate +# transaction node even without semi-sync slave connected, and would +# finally result in transaction node allocation error. +# +# Semi-sync master will pre-allocate 'max_connections' transaction +# nodes, so here we do more than that much transactions to check if it +# will fail or not. +# select @@global.max_connections + 1; +let $i= `select @@global.max_connections + 1`; +disable_query_log; +eval create table t1 (a int) engine=$engine_type; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} +drop table t1; +enable_query_log; + +# BUG#45673 +echo [ status of semi-sync on master should be OFF ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +disable_query_log; +# reset master to make sure the following test will start with a clean environment +reset master; +enable_query_log; + +--echo # +--echo # INSTALL PLUGIN semi-sync on slave +--echo # + +connection slave; +echo [ on slave ]; + +disable_query_log; +let $value= query_get_value(show variables like 'rpl_semi_sync_slave_enabled', Value, 1); +if (`select '$value' = 'No such row'`) +{ + set sql_log_bin=0; + INSTALL PLUGIN rpl_semi_sync_slave SONAME 'libsemisync_slave.so'; + set sql_log_bin=1; +} +enable_query_log; + +echo [ default state of semi-sync on slave should be OFF ]; +show variables like 'rpl_semi_sync_slave_enabled'; + +echo [ enable semi-sync on slave ]; +set global rpl_semi_sync_slave_enabled = 1; +show variables like 'rpl_semi_sync_slave_enabled'; +source include/start_slave.inc; + +connection master; +echo [ on master ]; + +# NOTE: Rpl_semi_sync_master_client will only be updated when +# semi-sync slave has started binlog dump request +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; + +echo [ initial master state after the semi-sync slave connected ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +replace_result $engine_type ENGINE_TYPE; +eval create table t1(n int) engine = $engine_type; + +echo [ master state after CREATE TABLE statement ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +let $i=300; +echo [ insert records to table ]; +disable_query_log; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} +enable_query_log; + +echo [ master status after inserts ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +sync_slave_with_master; +echo [ on slave ]; + +echo [ slave status after replicated inserts ]; +show status like 'Rpl_semi_sync_slave_status'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; + +source include/stop_slave.inc; + +connection master; +echo [ on master ]; + +# The first semi-sync check should be on because after slave stop, +# there are no transactions on the master. +echo [ master status should be ON ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; +show status like 'Rpl_semi_sync_master_clients'; + +echo [ semi-sync replication of these transactions will fail ]; +insert into t1 values (500); +delete from t1 where n < 500; +insert into t1 values (100); + +# The second semi-sync check should be off because one transaction +# times out during waiting. +echo [ master status should be OFF ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +# Save the master position for later use. +save_master_pos; + +connection slave; +echo [ on slave ]; + +echo [ slave status should be OFF ]; +show status like 'Rpl_semi_sync_slave_status'; +source include/start_slave.inc; +sync_with_master; + +echo [ slave status should be ON ]; +show status like 'Rpl_semi_sync_slave_status'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; + +connection master; +echo [ on master ]; + +echo [ do something to activate semi-sync ]; +drop table t1; + +# The third semi-sync check should be on again. +echo [ master status should be ON again ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; +show status like 'Rpl_semi_sync_master_clients'; + +sync_slave_with_master; +echo [ on slave ]; + +source include/stop_slave.inc; + +connection master; +echo [ on master ]; + +source include/show_master_logs.inc; +show variables like 'rpl_semi_sync_master_enabled'; + +echo [ disable semi-sync on the fly ]; +set global rpl_semi_sync_master_enabled=0; +show variables like 'rpl_semi_sync_master_enabled'; +show status like 'Rpl_semi_sync_master_status'; + +echo [ enable semi-sync on the fly ]; +set global rpl_semi_sync_master_enabled=1; +show variables like 'rpl_semi_sync_master_enabled'; +show status like 'Rpl_semi_sync_master_status'; + +connection slave; +echo [ on slave ]; + +source include/start_slave.inc; + +connection master; +echo [ on master ]; + +replace_result $engine_type ENGINE_TYPE; +eval create table t1 (a int) engine = $engine_type; +drop table t1; + +##show status like 'Rpl_semi_sync_master_status'; + +sync_slave_with_master; +--replace_column 2 # +show status like 'Rpl_relay%'; + +echo [ test reset master ]; +connection master; +echo [ on master]; + +reset master; + +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +connection slave; +echo [ on slave ]; + +source include/stop_slave.inc; +reset slave; + +# Kill the dump thread on master for previous slave connection and +# wait for it to exit +connection master; +let $_tid= `select id from information_schema.processlist where command = 'Binlog Dump' limit 1`; +if ($_tid) +{ + disable_query_log; + eval kill query $_tid; + enable_query_log; + + # After dump thread exit, Rpl_semi_sync_master_clients will be 0 + let $status_var= Rpl_semi_sync_master_clients; + let $status_var_value= 0; + source include/wait_for_status_var.inc; +} + +connection slave; +source include/start_slave.inc; + +connection master; +echo [ on master ]; + +# Wait for dump thread to start, Rpl_semi_sync_master_clients will be +# 1 after dump thread started. +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; + +replace_result $engine_type ENGINE_TYPE; +eval create table t1 (a int) engine = $engine_type; +insert into t1 values (1); +insert into t1 values (2), (3); + +sync_slave_with_master; +echo [ on slave ]; + +select * from t1; + +connection master; +echo [ on master ]; + +echo [ master semi-sync status should be ON ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +--echo # +--echo # Start semi-sync replication without SUPER privilege +--echo # +connection slave; +source include/stop_slave.inc; +reset slave; +connection master; +echo [ on master ]; +reset master; + +# Kill the dump thread on master for previous slave connection and wait for it to exit +let $_tid= `select id from information_schema.processlist where command = 'Binlog Dump' limit 1`; +if ($_tid) +{ + disable_query_log; + eval kill query $_tid; + enable_query_log; + + # After dump thread exit, Rpl_semi_sync_master_clients will be 0 + let $status_var= Rpl_semi_sync_master_clients; + let $status_var_value= 0; + source include/wait_for_status_var.inc; +} + +# Do not binlog the following statement because it will generate +# different events for ROW and STATEMENT format +set sql_log_bin=0; +grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl'; +flush privileges; +set sql_log_bin=1; +connection slave; +echo [ on slave ]; +grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl'; +flush privileges; +change master to master_user='rpl',master_password='rpl'; +source include/start_slave.inc; +show status like 'Rpl_semi_sync_slave_status'; +connection master; +echo [ on master ]; + +# Wait for the semi-sync binlog dump thread to start +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +echo [ master semi-sync should be ON ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; +insert into t1 values (4); +insert into t1 values (5); +echo [ master semi-sync should be ON ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +--echo # +--echo # Test semi-sync slave connect to non-semi-sync master +--echo # + +# Disable semi-sync on master +connection slave; +echo [ on slave ]; +source include/stop_slave.inc; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; + +connection master; +echo [ on master ]; + +# Kill the dump thread on master for previous slave connection and wait for it to exit +let $_tid= `select id from information_schema.processlist where command = 'Binlog Dump' limit 1`; +if ($_tid) +{ + disable_query_log; + eval kill query $_tid; + enable_query_log; + + # After dump thread exit, Rpl_semi_sync_master_clients will be 0 + let $status_var= Rpl_semi_sync_master_clients; + let $status_var_value= 0; + source include/wait_for_status_var.inc; +} + +echo [ Semi-sync status on master should be ON ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +set global rpl_semi_sync_master_enabled= 0; + +connection slave; +echo [ on slave ]; +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +source include/start_slave.inc; +connection master; +echo [ on master ]; +insert into t1 values (8); +echo [ master semi-sync clients should be 0, status should be OFF ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +sync_slave_with_master; +echo [ on slave ]; +show status like 'Rpl_semi_sync_slave_status'; + +# Uninstall semi-sync plugin on master +connection slave; +source include/stop_slave.inc; +connection master; +echo [ on master ]; +set sql_log_bin=0; +UNINSTALL PLUGIN rpl_semi_sync_master; +set sql_log_bin=1; +enable_query_log; +SHOW VARIABLES LIKE 'rpl_semi_sync_master_enabled'; + +connection slave; +echo [ on slave ]; +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +source include/start_slave.inc; + +connection master; +echo [ on master ]; +insert into t1 values (10); +sync_slave_with_master; +echo [ on slave ]; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; + +--echo # +--echo # Test non-semi-sync slave connect to semi-sync master +--echo # + +connection master; +set sql_log_bin=0; +INSTALL PLUGIN rpl_semi_sync_master SONAME 'libsemisync_master.so'; +set global rpl_semi_sync_master_timeout= 5000; /* 5s */ +set sql_log_bin=1; +set global rpl_semi_sync_master_enabled= 1; + +connection slave; +echo [ on slave ]; +source include/stop_slave.inc; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; + +echo [ uninstall semi-sync slave plugin ]; +UNINSTALL PLUGIN rpl_semi_sync_slave; +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +source include/start_slave.inc; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +source include/stop_slave.inc; + +echo [ reinstall semi-sync slave plugin and disable semi-sync ]; +INSTALL PLUGIN rpl_semi_sync_slave SONAME 'libsemisync_slave.so'; +set global rpl_semi_sync_slave_enabled= 0; +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +source include/start_slave.inc; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; + +--echo # +--echo # Clean up +--echo # + +connection slave; +source include/stop_slave.inc; +UNINSTALL PLUGIN rpl_semi_sync_slave; + +connection master; +UNINSTALL PLUGIN rpl_semi_sync_master; + +connection slave; +source include/start_slave.inc; + +connection master; +drop table t1; +drop user rpl@127.0.0.1; +flush privileges; +sync_slave_with_master; From 12e822039d5dde7eda9f701323ff3b7b6c36bc29 Mon Sep 17 00:00:00 2001 From: Guilhem Bichot Date: Wed, 30 Sep 2009 12:25:50 +0200 Subject: [PATCH 042/274] Fix for BUG#42980 "Client doesn't set NUM_FLAG for DECIMAL and TIMESTAMP": DECIMAL and TIMESTAMP used to have NUM_FLAG, but NEWDECIMAL was forgotten. It's correct that TIMESTAMP does not have the flag nowadays (manual will be updated, connectors developers will be notified). client/mysqldump.c: IS_NUM_FIELD(f) removed and replaced by its definition (f>flags & NUM_FLAG). include/mysql.h: - IS_NUM_FIELD() is removed because name is too close to IS_NUM() and it is not used a lot - INTERNAL_NUM_FIELD() is removed: * it forgets to test NEWDECIMAL (when IS_NUM() was updated for NEWDECIMAL we forgot to update INTERNAL_NUM_FIELD()), that's why client didn't mark NEWDECIMAL with NUM_FLAG (a bug). * it has an obsolete test for length of the TIMESTAMP field: test became accidentally wrong when length of TIMESTAMP was changed to always be 19 (when the format was changed from YYYYMMDDhhmmss to YYYY-MM-DD hh:mm:ss), never 8 or 14 anymore. That obsolete test caused TIMESTAMP to lose NUM_FLAG, which was an accidental but good change (see below). * IS_NUM() should be used instead - IS_NUM(f) is changed: TIMESTAMP used to be parsable as a number without quotes (when it was formatted as "YYYYMMDDhhmmss"); but it is not anymore (now that it is "YYYY-MM-DD hh:mm:ss"), so it should not have NUM_FLAG (mysqldump needs to quote TIMESTAMP values), so IS_NUM() should return false for it. libmysqld/lib_sql.cc: use IS_NUM() instead of INTERNAL_NUM_FIELD() mysql-test/r/bigint.result: result change: NEWDECIMAL fields now have NUM_FLAG (32768) mysql-test/r/metadata.result: result change: NEWDECIMAL fields now have NUM_FLAG (32768) mysql-test/r/mysqldump.result: DECIMAL columns are not quoted anymore by mysqldump. Which is ok, the parser does not need '' for them mysql-test/r/ps_2myisam.result: result change: NEWDECIMAL fields now have NUM_FLAG (32768) mysql-test/r/ps_3innodb.result: result change: NEWDECIMAL fields now have NUM_FLAG (32768) mysql-test/r/ps_4heap.result: result change: NEWDECIMAL fields now have NUM_FLAG (32768) mysql-test/r/ps_5merge.result: result change: NEWDECIMAL fields now have NUM_FLAG (32768) mysql-test/suite/ndb/r/ps_7ndb.result: result change: NEWDECIMAL fields now have NUM_FLAG (32768) mysql-test/t/metadata.test: test for BUG#42980 sql-common/client.c: use IS_NUM() instead of INTERNAL_NUM_FIELD() --- client/mysqldump.c | 4 +- include/mysql.h | 8 ++- libmysqld/lib_sql.cc | 2 +- mysql-test/r/bigint.result | 2 +- mysql-test/r/metadata.result | 96 ++++++++++++++++++++++++++- mysql-test/r/mysqldump.result | 10 +-- mysql-test/r/ps_2myisam.result | 42 ++++++------ mysql-test/r/ps_3innodb.result | 42 ++++++------ mysql-test/r/ps_4heap.result | 42 ++++++------ mysql-test/r/ps_5merge.result | 84 +++++++++++------------ mysql-test/suite/ndb/r/ps_7ndb.result | 42 ++++++------ mysql-test/t/metadata.test | 57 ++++++++++++++++ sql-common/client.c | 4 +- 13 files changed, 293 insertions(+), 142 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index e9e3124b9cb..22d3f376e3e 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -3316,7 +3316,7 @@ static void dump_table(char *table, char *db) { if (length) { - if (!IS_NUM_FIELD(field)) + if (!(field->flags & NUM_FLAG)) { /* "length * 2 + 2" is OK for both HEX and non-HEX modes: @@ -3384,7 +3384,7 @@ static void dump_table(char *table, char *db) } if (row[i]) { - if (!IS_NUM_FIELD(field)) + if (!(field->flags & NUM_FLAG)) { if (opt_xml) { diff --git a/include/mysql.h b/include/mysql.h index d114afb6c93..70faf3cb2c1 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -86,9 +86,11 @@ extern char *mysql_unix_port; #define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG) #define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG) #define IS_BLOB(n) ((n) & BLOB_FLAG) -#define IS_NUM(t) ((t) <= MYSQL_TYPE_INT24 || (t) == MYSQL_TYPE_YEAR || (t) == MYSQL_TYPE_NEWDECIMAL) -#define IS_NUM_FIELD(f) ((f)->flags & NUM_FLAG) -#define INTERNAL_NUM_FIELD(f) (((f)->type <= MYSQL_TYPE_INT24 && ((f)->type != MYSQL_TYPE_TIMESTAMP || (f)->length == 14 || (f)->length == 8)) || (f)->type == MYSQL_TYPE_YEAR) +/** + Returns true if the value is a number which does not need quotes for + the sql_lex.cc parser to parse correctly. +*/ +#define IS_NUM(t) (((t) <= MYSQL_TYPE_INT24 && (t) != MYSQL_TYPE_TIMESTAMP) || (t) == MYSQL_TYPE_YEAR || (t) == MYSQL_TYPE_NEWDECIMAL) #define IS_LONGDATA(t) ((t) >= MYSQL_TYPE_TINY_BLOB && (t) <= MYSQL_TYPE_STRING) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 64822f8fad6..4b3822dd250 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -952,7 +952,7 @@ bool Protocol::send_fields(List *list, uint flags) client_field->catalog= dup_str_aux(field_alloc, "def", 3, cs, thd_cs); client_field->catalog_length= 3; - if (INTERNAL_NUM_FIELD(client_field)) + if (IS_NUM(client_field->type)) client_field->flags|= NUM_FLAG; if (flags & (int) Protocol::SEND_DEFAULTS) diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index 7c23f1267c2..6b0954655e9 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -385,7 +385,7 @@ def -((9223372036854775808)) 8 20 20 N 32897 0 63 -9223372036854775808 select -(-(9223372036854775808)); Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def -(-(9223372036854775808)) 246 21 19 N 129 0 63 +def -(-(9223372036854775808)) 246 21 19 N 32897 0 63 -(-(9223372036854775808)) 9223372036854775808 select --9223372036854775808, ---9223372036854775808, ----9223372036854775808; diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 6b498e55d85..58dd97ee9f3 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -2,7 +2,7 @@ drop table if exists t1,t2; select 1, 1.0, -1, "hello", NULL; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def 1 8 1 1 N 32897 0 63 -def 1.0 246 4 3 N 129 1 63 +def 1.0 246 4 3 N 32897 1 63 def -1 8 2 2 N 32897 0 63 def hello 253 5 5 N 1 31 8 def NULL 6 0 0 Y 32896 0 63 @@ -18,7 +18,7 @@ def test t1 t1 d d 3 11 0 Y 32768 0 63 def test t1 t1 e e 8 20 0 Y 32768 0 63 def test t1 t1 f f 4 3 0 Y 32768 2 63 def test t1 t1 g g 5 4 0 Y 32768 3 63 -def test t1 t1 h h 246 7 0 Y 0 4 63 +def test t1 t1 h h 246 7 0 Y 32768 4 63 def test t1 t1 i i 13 4 0 Y 32864 0 63 def test t1 t1 j j 10 10 0 Y 128 0 63 def test t1 t1 k k 7 19 0 N 9441 0 63 @@ -199,3 +199,95 @@ def IFNULL(d, d) IFNULL(d, d) 10 10 10 Y 128 0 63 def LEAST(d, d) LEAST(d, d) 10 10 10 Y 128 0 63 DROP TABLE t1; End of 5.0 tests +create table t1( +# numeric types +bool_col bool, +boolean_col boolean, +bit_col bit(5), +tiny tinyint, +tiny_uns tinyint unsigned, +small smallint, +small_uns smallint unsigned, +medium mediumint, +medium_uns mediumint unsigned, +int_col int, +int_col_uns int unsigned, +big bigint, +big_uns bigint unsigned, +decimal_col decimal(10,5), +# synonyms of DECIMAL +numeric_col numeric(10), +fixed_col fixed(10), +dec_col dec(10), +decimal_col_uns decimal(10,5) unsigned, +fcol float, +fcol_uns float unsigned, +dcol double, +double_precision_col double precision, +dcol_uns double unsigned, +# date/time types +date_col date, +time_col time, +timestamp_col timestamp, +year_col year, +datetime_col datetime, +# string types +char_col char(5), +varchar_col varchar(10), +binary_col binary(10), +varbinary_col varbinary(10), +tinyblob_col tinyblob, +blob_col blob, +mediumblob_col mediumblob, +longblob_col longblob, +text_col text, +mediumtext_col mediumtext, +longtext_col longtext, +enum_col enum("A","B","C"), +set_col set("F","E","D") +); +select * from t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 bool_col bool_col 1 1 0 Y 32768 0 63 +def test t1 t1 boolean_col boolean_col 1 1 0 Y 32768 0 63 +def test t1 t1 bit_col bit_col 16 5 0 Y 32 0 63 +def test t1 t1 tiny tiny 1 4 0 Y 32768 0 63 +def test t1 t1 tiny_uns tiny_uns 1 3 0 Y 32800 0 63 +def test t1 t1 small small 2 6 0 Y 32768 0 63 +def test t1 t1 small_uns small_uns 2 5 0 Y 32800 0 63 +def test t1 t1 medium medium 9 9 0 Y 32768 0 63 +def test t1 t1 medium_uns medium_uns 9 8 0 Y 32800 0 63 +def test t1 t1 int_col int_col 3 11 0 Y 32768 0 63 +def test t1 t1 int_col_uns int_col_uns 3 10 0 Y 32800 0 63 +def test t1 t1 big big 8 20 0 Y 32768 0 63 +def test t1 t1 big_uns big_uns 8 20 0 Y 32800 0 63 +def test t1 t1 decimal_col decimal_col 246 12 0 Y 32768 5 63 +def test t1 t1 numeric_col numeric_col 246 11 0 Y 32768 0 63 +def test t1 t1 fixed_col fixed_col 246 11 0 Y 32768 0 63 +def test t1 t1 dec_col dec_col 246 11 0 Y 32768 0 63 +def test t1 t1 decimal_col_uns decimal_col_uns 246 11 0 Y 32800 5 63 +def test t1 t1 fcol fcol 4 12 0 Y 32768 31 63 +def test t1 t1 fcol_uns fcol_uns 4 12 0 Y 32800 31 63 +def test t1 t1 dcol dcol 5 22 0 Y 32768 31 63 +def test t1 t1 double_precision_col double_precision_col 5 22 0 Y 32768 31 63 +def test t1 t1 dcol_uns dcol_uns 5 22 0 Y 32800 31 63 +def test t1 t1 date_col date_col 10 10 0 Y 128 0 63 +def test t1 t1 time_col time_col 11 8 0 Y 128 0 63 +def test t1 t1 timestamp_col timestamp_col 7 19 0 N 9441 0 63 +def test t1 t1 year_col year_col 13 4 0 Y 32864 0 63 +def test t1 t1 datetime_col datetime_col 12 19 0 Y 128 0 63 +def test t1 t1 char_col char_col 254 5 0 Y 0 0 8 +def test t1 t1 varchar_col varchar_col 253 10 0 Y 0 0 8 +def test t1 t1 binary_col binary_col 254 10 0 Y 128 0 63 +def test t1 t1 varbinary_col varbinary_col 253 10 0 Y 128 0 63 +def test t1 t1 tinyblob_col tinyblob_col 252 255 0 Y 144 0 63 +def test t1 t1 blob_col blob_col 252 65535 0 Y 144 0 63 +def test t1 t1 mediumblob_col mediumblob_col 252 16777215 0 Y 144 0 63 +def test t1 t1 longblob_col longblob_col 252 4294967295 0 Y 144 0 63 +def test t1 t1 text_col text_col 252 65535 0 Y 16 0 8 +def test t1 t1 mediumtext_col mediumtext_col 252 16777215 0 Y 16 0 8 +def test t1 t1 longtext_col longtext_col 252 4294967295 0 Y 16 0 8 +def test t1 t1 enum_col enum_col 254 1 0 Y 256 0 8 +def test t1 t1 set_col set_col 254 5 0 Y 2048 0 8 +bool_col boolean_col bit_col tiny tiny_uns small small_uns medium medium_uns int_col int_col_uns big big_uns decimal_col numeric_col fixed_col dec_col decimal_col_uns fcol fcol_uns dcol double_precision_col dcol_uns date_col time_col timestamp_col year_col datetime_col char_col varchar_col binary_col varbinary_col tinyblob_col blob_col mediumblob_col longblob_col text_col mediumtext_col longtext_col enum_col set_col +drop table t1; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 8162e1aca05..e4889b86987 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -40,7 +40,7 @@ CREATE TABLE `t1` ( `a` decimal(64,20) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `t1` VALUES ('1234567890123456789012345678901234567890.00000000000000000000'),('987654321098765432109876543210987654321.00000000000000000000'); +INSERT INTO `t1` VALUES (1234567890123456789012345678901234567890.00000000000000000000),(987654321098765432109876543210987654321.00000000000000000000); DROP TABLE t1; # # Bug#2055 mysqldump should replace "-inf" numeric field values with "NULL" @@ -77,7 +77,7 @@ CREATE TABLE `t1` ( `b` float DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); +INSERT INTO `t1` VALUES (1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `t1` ( @@ -85,7 +85,7 @@ CREATE TABLE `t1` ( `b` float DEFAULT NULL ); /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); +INSERT INTO `t1` VALUES (1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456); /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -108,7 +108,7 @@ CREATE TABLE `t1` ( LOCK TABLES `t1` WRITE; /*!40000 ALTER TABLE `t1` DISABLE KEYS */; -INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); +INSERT INTO `t1` VALUES (1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456); /*!40000 ALTER TABLE `t1` ENABLE KEYS */; UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; @@ -135,7 +135,7 @@ CREATE TABLE `t1` ( ); /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); +INSERT INTO `t1` VALUES (1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456); /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index a91d13d11a1..c51863b73f7 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -59,8 +59,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 246 9 6 Y 0 4 63 -def test t9 t9 c12 c12 246 10 6 Y 0 4 63 +def test t9 t9 c11 c11 246 9 6 Y 32768 4 63 +def test t9 t9 c12 c12 246 10 6 Y 32768 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 9441 0 63 @@ -1807,8 +1807,8 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 -def test t5 t5 param02 param02 246 67 32 Y 0 30 63 +def test t5 t5 const02 const02 246 4 3 N 32769 1 63 +def test t5 t5 param02 param02 246 67 32 Y 32768 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 @@ -1829,7 +1829,7 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 246 67 0 Y 0 30 63 +def test t5 t5 param13 param13 246 67 0 Y 32768 30 63 def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 @@ -1927,8 +1927,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -1974,8 +1974,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2024,8 +2024,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2064,8 +2064,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2112,8 +2112,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2156,8 +2156,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2202,8 +2202,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2240,8 +2240,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 50c94d6cc4e..2670451f24e 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -59,8 +59,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 246 9 6 Y 0 4 63 -def test t9 t9 c12 c12 246 10 6 Y 0 4 63 +def test t9 t9 c11 c11 246 9 6 Y 32768 4 63 +def test t9 t9 c12 c12 246 10 6 Y 32768 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 9441 0 63 @@ -1790,8 +1790,8 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 -def test t5 t5 param02 param02 246 67 32 Y 0 30 63 +def test t5 t5 const02 const02 246 4 3 N 32769 1 63 +def test t5 t5 param02 param02 246 67 32 Y 32768 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 @@ -1812,7 +1812,7 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 246 67 0 Y 0 30 63 +def test t5 t5 param13 param13 246 67 0 Y 32768 30 63 def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 @@ -1910,8 +1910,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -1957,8 +1957,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2007,8 +2007,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2047,8 +2047,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2095,8 +2095,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2139,8 +2139,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2185,8 +2185,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2223,8 +2223,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index a85809d3800..4372c470b2d 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -60,8 +60,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 246 9 6 Y 0 4 63 -def test t9 t9 c12 c12 246 10 6 Y 0 4 63 +def test t9 t9 c11 c11 246 9 6 Y 32768 4 63 +def test t9 t9 c12 c12 246 10 6 Y 32768 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 9441 0 63 @@ -1791,8 +1791,8 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 -def test t5 t5 param02 param02 246 67 32 Y 0 30 63 +def test t5 t5 const02 const02 246 4 3 N 32769 1 63 +def test t5 t5 param02 param02 246 67 32 Y 32768 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 @@ -1813,7 +1813,7 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 246 67 0 Y 0 30 63 +def test t5 t5 param13 param13 246 67 0 Y 32768 30 63 def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 @@ -1911,8 +1911,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -1958,8 +1958,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2008,8 +2008,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2048,8 +2048,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2096,8 +2096,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2140,8 +2140,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2186,8 +2186,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2224,8 +2224,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index fd1b69c0ffd..35a43f7c032 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -102,8 +102,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 246 9 6 Y 0 4 63 -def test t9 t9 c12 c12 246 10 6 Y 0 4 63 +def test t9 t9 c11 c11 246 9 6 Y 32768 4 63 +def test t9 t9 c12 c12 246 10 6 Y 32768 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 9441 0 63 @@ -1727,8 +1727,8 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 -def test t5 t5 param02 param02 246 67 32 Y 0 30 63 +def test t5 t5 const02 const02 246 4 3 N 32769 1 63 +def test t5 t5 param02 param02 246 67 32 Y 32768 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 @@ -1749,7 +1749,7 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 246 67 0 Y 0 30 63 +def test t5 t5 param13 param13 246 67 0 Y 32768 30 63 def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 @@ -1847,8 +1847,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -1894,8 +1894,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -1944,8 +1944,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -1984,8 +1984,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2032,8 +2032,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2076,8 +2076,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2122,8 +2122,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2160,8 +2160,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -3124,8 +3124,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 246 9 6 Y 0 4 63 -def test t9 t9 c12 c12 246 10 6 Y 0 4 63 +def test t9 t9 c11 c11 246 9 6 Y 32768 4 63 +def test t9 t9 c12 c12 246 10 6 Y 32768 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 9441 0 63 @@ -4749,8 +4749,8 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 -def test t5 t5 param02 param02 246 67 32 Y 0 30 63 +def test t5 t5 const02 const02 246 4 3 N 32769 1 63 +def test t5 t5 param02 param02 246 67 32 Y 32768 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 @@ -4771,7 +4771,7 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 246 67 0 Y 0 30 63 +def test t5 t5 param13 param13 246 67 0 Y 32768 30 63 def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 @@ -4869,8 +4869,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -4916,8 +4916,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -4966,8 +4966,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -5006,8 +5006,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -5054,8 +5054,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -5098,8 +5098,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -5144,8 +5144,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -5182,8 +5182,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 diff --git a/mysql-test/suite/ndb/r/ps_7ndb.result b/mysql-test/suite/ndb/r/ps_7ndb.result index 73a2e0c1dda..e57fdcb6df6 100644 --- a/mysql-test/suite/ndb/r/ps_7ndb.result +++ b/mysql-test/suite/ndb/r/ps_7ndb.result @@ -59,8 +59,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 246 9 6 Y 0 4 63 -def test t9 t9 c12 c12 246 10 6 Y 0 4 63 +def test t9 t9 c11 c11 246 9 6 Y 32768 4 63 +def test t9 t9 c12 c12 246 10 6 Y 32768 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 9441 0 63 @@ -1790,8 +1790,8 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 4 3 N 1 1 63 -def test t5 t5 param02 param02 246 67 32 Y 0 30 63 +def test t5 t5 const02 const02 246 4 3 N 32769 1 63 +def test t5 t5 param02 param02 246 67 32 Y 32768 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 @@ -1812,7 +1812,7 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 246 67 0 Y 0 30 63 +def test t5 t5 param13 param13 246 67 0 Y 32768 30 63 def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 @@ -1910,8 +1910,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -1957,8 +1957,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2007,8 +2007,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2047,8 +2047,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2095,8 +2095,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2139,8 +2139,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2185,8 +2185,8 @@ def @arg07 5 23 1 Y 32896 31 63 def @arg08 5 23 1 Y 32896 31 63 def @arg09 5 23 1 Y 32896 31 63 def @arg10 5 23 1 Y 32896 31 63 -def @arg11 246 83 6 Y 128 30 63 -def @arg12 246 83 6 Y 128 30 63 +def @arg11 246 83 6 Y 32896 30 63 +def @arg12 246 83 6 Y 32896 30 63 def @arg13 251 16777216 10 Y 128 31 63 def @arg14 251 16777216 19 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 @@ -2223,8 +2223,8 @@ def @arg07 5 23 0 Y 32896 31 63 def @arg08 5 23 0 Y 32896 31 63 def @arg09 5 23 0 Y 32896 31 63 def @arg10 5 23 0 Y 32896 31 63 -def @arg11 246 83 0 Y 128 30 63 -def @arg12 246 83 0 Y 128 30 63 +def @arg11 246 83 0 Y 32896 30 63 +def @arg12 246 83 0 Y 32896 30 63 def @arg13 251 16777216 0 Y 128 31 63 def @arg14 251 16777216 0 Y 128 31 63 def @arg15 251 16777216 19 Y 128 31 63 diff --git a/mysql-test/t/metadata.test b/mysql-test/t/metadata.test index a10767579fb..a42dcfd618d 100644 --- a/mysql-test/t/metadata.test +++ b/mysql-test/t/metadata.test @@ -130,3 +130,60 @@ SELECT COALESCE(d, d), IFNULL(d, d), IF(i, d, d), DROP TABLE t1; --echo End of 5.0 tests + +# Verify that column metadata is correct for all possible data types. +# Originally about BUG#42980 "Client doesn't set NUM_FLAG for DECIMAL" + +create table t1( +# numeric types +bool_col bool, +boolean_col boolean, +bit_col bit(5), +tiny tinyint, +tiny_uns tinyint unsigned, +small smallint, +small_uns smallint unsigned, +medium mediumint, +medium_uns mediumint unsigned, +int_col int, +int_col_uns int unsigned, +big bigint, +big_uns bigint unsigned, +decimal_col decimal(10,5), +# synonyms of DECIMAL +numeric_col numeric(10), +fixed_col fixed(10), +dec_col dec(10), +decimal_col_uns decimal(10,5) unsigned, +fcol float, +fcol_uns float unsigned, +dcol double, +double_precision_col double precision, +dcol_uns double unsigned, +# date/time types +date_col date, +time_col time, +timestamp_col timestamp, +year_col year, +datetime_col datetime, +# string types +char_col char(5), +varchar_col varchar(10), +binary_col binary(10), +varbinary_col varbinary(10), +tinyblob_col tinyblob, +blob_col blob, +mediumblob_col mediumblob, +longblob_col longblob, +text_col text, +mediumtext_col mediumtext, +longtext_col longtext, +enum_col enum("A","B","C"), +set_col set("F","E","D") +); + +--enable_metadata +select * from t1; +--disable_metadata + +drop table t1; diff --git a/sql-common/client.c b/sql-common/client.c index 84029b449af..a502e0ea195 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1313,7 +1313,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, field->flags= uint2korr(pos+7); field->decimals= (uint) pos[9]; - if (INTERNAL_NUM_FIELD(field)) + if (IS_NUM(field->type)) field->flags|= NUM_FLAG; if (default_value && row->data[7]) { @@ -1354,7 +1354,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, field->flags= (uint) (uchar) row->data[4][0]; field->decimals=(uint) (uchar) row->data[4][1]; } - if (INTERNAL_NUM_FIELD(field)) + if (IS_NUM(field->type)) field->flags|= NUM_FLAG; if (default_value && row->data[5]) { From 7dacca0ff0a3c28401500afc807b71ebe9e4594f Mon Sep 17 00:00:00 2001 From: Ingo Struewing Date: Wed, 30 Sep 2009 12:28:15 +0200 Subject: [PATCH 043/274] Bug#37267 - connect() EINPROGRESS failures mishandled in client library We cann connect() in a non-blocking mode to be able to specify a non-standard timeout. The problem was that we did not fetch the status from the non-blocking connect(). We assumed that poll() would not return a POLLIN flag if the connect failed. But on some platforms this is not true. After a successful poll() we do now retrieve the status value from connect() with getsockopt(...SO_ERROR...). Now we do know if (and how) the connect failed. The test case for my investigation was rpl.rlp_ssl1 on an Ubuntu 9.04 x86_64 machine. Both, IPV4 and IPV6 were active. 'localhost' resolved first for IPV6 and then for IPV4. The connection over IPV6 was blocked. rpl.rlp_ssl1 timed out as it did not notice the failed connect(). The first read() failed, which was interpreted as a master crash and the connection was tried to reestablish with the same result until the retry limit was reached. With the fix, the connect() problem is immediately recognized, and the connect() is retried on the second resolution for 'localhost', which is successful. libmysqld/libmysqld.c: Bug#37267 - connect() EINPROGRESS failures mishandled in client library Changed a DBUG print string to distinguish the two mysql_real_connect() implementations in DBUG traces. mysql-test/include/wait_for_slave_param.inc: Bug#37267 - connect() EINPROGRESS failures mishandled in client library Made timeout value available in error message. mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result: Bug#37267 - connect() EINPROGRESS failures mishandled in client library Fixed test result. Connect error is now detected as CR_CONN_HOST_ERROR (2003) instead of CR_SERVER_LOST (2013). sql-common/client.c: Bug#37267 - connect() EINPROGRESS failures mishandled in client library Added retrieval of the error code from the non-blocking connect(). Added DBUG. Added comment. --- libmysqld/libmysqld.c | 2 +- mysql-test/include/wait_for_slave_param.inc | 4 +- .../r/rpl_get_master_version_and_clock.result | 4 +- sql-common/client.c | 77 +++++++++++++++---- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index aff9391e015..31ad8844650 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -99,7 +99,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, char name_buff[USERNAME_LENGTH]; DBUG_ENTER("mysql_real_connect"); - DBUG_PRINT("enter",("host: %s db: %s user: %s", + DBUG_PRINT("enter",("host: %s db: %s user: %s (libmysqld)", host ? host : "(Null)", db ? db : "(Null)", user ? user : "(Null)")); diff --git a/mysql-test/include/wait_for_slave_param.inc b/mysql-test/include/wait_for_slave_param.inc index 82e57922913..1e690bdfe9c 100644 --- a/mysql-test/include/wait_for_slave_param.inc +++ b/mysql-test/include/wait_for_slave_param.inc @@ -49,6 +49,8 @@ if (!$_slave_timeout_counter) { let $_slave_timeout_counter= 3000; } +# Save resulting counter for later use. +let $slave_tcnt= $_slave_timeout_counter; let $_slave_param_comparison= $slave_param_comparison; if (`SELECT '$_slave_param_comparison' = ''`) @@ -70,7 +72,7 @@ while (`SELECT NOT('$_show_slave_status_value' $_slave_param_comparison '$slave_ # This has to be outside the loop until BUG#41913 has been fixed if (!$_slave_timeout_counter) { - --echo **** ERROR: timeout after $slave_timeout seconds while waiting for slave parameter $slave_param $_slave_param_comparison $slave_param_value **** + --echo **** ERROR: timeout after $slave_tcnt deci-seconds while waiting for slave parameter $slave_param $_slave_param_comparison $slave_param_value **** if (`SELECT '$slave_error_message' != ''`) { --echo Message: $slave_error_message diff --git a/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result b/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result index 99a0fd21f66..3321b9b4969 100644 --- a/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result +++ b/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result @@ -18,7 +18,7 @@ start slave; SELECT RELEASE_LOCK("debug_lock.before_get_UNIX_TIMESTAMP"); RELEASE_LOCK("debug_lock.before_get_UNIX_TIMESTAMP") 1 -Slave_IO_Errno= 2013 +Slave_IO_Errno= 2003 SELECT IS_FREE_LOCK("debug_lock.before_get_SERVER_ID"); IS_FREE_LOCK("debug_lock.before_get_SERVER_ID") 1 @@ -31,7 +31,7 @@ start slave; SELECT RELEASE_LOCK("debug_lock.before_get_SERVER_ID"); RELEASE_LOCK("debug_lock.before_get_SERVER_ID") 1 -Slave_IO_Errno= 2013 +Slave_IO_Errno= 2003 set global debug= ''; reset master; include/stop_slave.inc diff --git a/sql-common/client.c b/sql-common/client.c index 84029b449af..1c0262f3414 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -145,9 +145,12 @@ int my_connect(my_socket fd, const struct sockaddr *name, uint namelen, uint timeout) { #if defined(__WIN__) || defined(__NETWARE__) - return connect(fd, (struct sockaddr*) name, namelen); + DBUG_ENTER("my_connect"); + DBUG_RETURN(connect(fd, (struct sockaddr*) name, namelen)); #else int flags, res, s_err; + DBUG_ENTER("my_connect"); + DBUG_PRINT("enter", ("fd: %d timeout: %u", fd, timeout)); /* If they passed us a timeout of zero, we should behave @@ -155,24 +158,26 @@ int my_connect(my_socket fd, const struct sockaddr *name, uint namelen, */ if (timeout == 0) - return connect(fd, (struct sockaddr*) name, namelen); + DBUG_RETURN(connect(fd, (struct sockaddr*) name, namelen)); flags = fcntl(fd, F_GETFL, 0); /* Set socket to not block */ #ifdef O_NONBLOCK fcntl(fd, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */ #endif + DBUG_PRINT("info", ("connecting non-blocking")); res= connect(fd, (struct sockaddr*) name, namelen); + DBUG_PRINT("info", ("connect result: %d errno: %d", res, errno)); s_err= errno; /* Save the error... */ fcntl(fd, F_SETFL, flags); if ((res != 0) && (s_err != EINPROGRESS)) { errno= s_err; /* Restore it */ - return(-1); + DBUG_RETURN(-1); } if (res == 0) /* Connected quickly! */ - return(0); - return wait_for_data(fd, timeout); + DBUG_RETURN(0); + DBUG_RETURN(wait_for_data(fd, timeout)); #endif } @@ -191,26 +196,58 @@ static int wait_for_data(my_socket fd, uint timeout) #ifdef HAVE_POLL struct pollfd ufds; int res; + DBUG_ENTER("wait_for_data"); + DBUG_PRINT("info", ("polling")); ufds.fd= fd; ufds.events= POLLIN | POLLPRI; if (!(res= poll(&ufds, 1, (int) timeout*1000))) { + DBUG_PRINT("info", ("poll timed out")); errno= EINTR; - return -1; + DBUG_RETURN(-1); } + DBUG_PRINT("info", + ("poll result: %d errno: %d revents: 0x%02d events: 0x%02d", + res, errno, ufds.revents, ufds.events)); if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI))) - return -1; - return 0; + DBUG_RETURN(-1); + /* + At this point, we know that something happened on the socket. + But this does not means that everything is alright. + The connect might have failed. We need to retrieve the error code + from the socket layer. We must return success only if we are sure + that it was really a success. Otherwise we might prevent the caller + from trying another address to connect to. + */ + { + int s_err; + socklen_t s_len= sizeof(s_err); + + DBUG_PRINT("info", ("Get SO_ERROR from non-blocked connected socket.")); + res= getsockopt(fd, SOL_SOCKET, SO_ERROR, &s_err, &s_len); + DBUG_PRINT("info", ("getsockopt res: %d s_err: %d", res, s_err)); + if (res) + DBUG_RETURN(res); + /* getsockopt() was successful, check the retrieved status value. */ + if (s_err) + { + errno= s_err; + DBUG_RETURN(-1); + } + /* Status from connect() is zero. Socket is successfully connected. */ + } + DBUG_RETURN(0); #else SOCKOPT_OPTLEN_TYPE s_err_size = sizeof(uint); fd_set sfds; struct timeval tv; time_t start_time, now_time; int res, s_err; + DBUG_ENTER("wait_for_data"); if (fd >= FD_SETSIZE) /* Check if wrong error */ - return 0; /* Can't use timeout */ + DBUG_RETURN(0); /* Can't use timeout */ /* Our connection is "in progress." We can use the select() call to wait @@ -250,11 +287,11 @@ static int wait_for_data(my_socket fd, uint timeout) break; #endif if (res == 0) /* timeout */ - return -1; + DBUG_RETURN(-1); now_time= my_time(0); timeout-= (uint) (now_time - start_time); if (errno != EINTR || (int) timeout <= 0) - return -1; + DBUG_RETURN(-1); } /* @@ -265,14 +302,14 @@ static int wait_for_data(my_socket fd, uint timeout) s_err=0; if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0) - return(-1); + DBUG_RETURN(-1); if (s_err) { /* getsockopt could succeed */ errno = s_err; - return(-1); /* but return an error... */ + DBUG_RETURN(-1); /* but return an error... */ } - return (0); /* ok */ + DBUG_RETURN(0); /* ok */ #endif /* HAVE_POLL */ } #endif /* defined(__WIN__) || defined(__NETWARE__) */ @@ -1877,7 +1914,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, init_sigpipe_variables DBUG_ENTER("mysql_real_connect"); - DBUG_PRINT("enter",("host: %s db: %s user: %s", + DBUG_PRINT("enter",("host: %s db: %s user: %s (client)", host ? host : "(Null)", db ? db : "(Null)", user ? user : "(Null)")); @@ -1927,6 +1964,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, unix_socket=mysql->options.unix_socket; mysql->server_status=SERVER_STATUS_AUTOCOMMIT; + DBUG_PRINT("info", ("Connecting")); /* Part 0: Grab a socket and connect it to the server @@ -1936,6 +1974,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) && (!host || !strcmp(host,LOCAL_HOST))) { + DBUG_PRINT("info", ("Using shared memory")); if ((create_shared_memory(mysql,net, mysql->options.connect_timeout)) == INVALID_HANDLE_VALUE) { @@ -2034,6 +2073,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, } } #endif + DBUG_PRINT("info", ("net->vio: %p protocol: %d", + net->vio, mysql->options.protocol)); if (!net->vio && (!mysql->options.protocol || mysql->options.protocol == MYSQL_PROTOCOL_TCP)) @@ -2105,6 +2146,11 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, min(sizeof(sock_addr.sin_addr), (size_t) hp->h_length)); DBUG_PRINT("info",("Trying %s...", (my_inet_ntoa(sock_addr.sin_addr, ipaddr), ipaddr))); + /* + Here we rely on my_connect() to return success only if the + connect attempt was really successful. Otherwise we would stop + trying another address, believing we were successful. + */ status= my_connect(sock, (struct sockaddr *) &sock_addr, sizeof(sock_addr), mysql->options.connect_timeout); } @@ -2163,6 +2209,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, /* Part 1: Connection established, read and parse first packet */ + DBUG_PRINT("info", ("Read first packet.")); if ((pkt_length=cli_safe_read(mysql)) == packet_error) { From 43fe9e045c4c84bdb84d61d0dc364576d1691a30 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Wed, 30 Sep 2009 19:36:35 +0800 Subject: [PATCH 044/274] Backporting BUG#40244 Optimized build of mysqld crashes when built with Sun Studio on SPARC --- sql/rpl_handler.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc index aea838928b9..da7aade5b99 100644 --- a/sql/rpl_handler.cc +++ b/sql/rpl_handler.cc @@ -88,11 +88,11 @@ int get_user_var_str(const char *name, char *value, int delegates_init() { - static unsigned char trans_mem[sizeof(Trans_delegate)]; - static unsigned char storage_mem[sizeof(Binlog_storage_delegate)]; + static unsigned long trans_mem[sizeof(Trans_delegate) / sizeof(unsigned long) + 1]; + static unsigned long storage_mem[sizeof(Binlog_storage_delegate) / sizeof(unsigned long) + 1]; #ifdef HAVE_REPLICATION - static unsigned char transmit_mem[sizeof(Binlog_transmit_delegate)]; - static unsigned char relay_io_mem[sizeof(Binlog_relay_IO_delegate)]; + static unsigned long transmit_mem[sizeof(Binlog_transmit_delegate) / sizeof(unsigned long) + 1]; + static unsigned long relay_io_mem[sizeof(Binlog_relay_IO_delegate)/ sizeof(unsigned long) + 1]; #endif if (!(transaction_delegate= new (trans_mem) Trans_delegate) From eaba74fee5611369c02e50eb6da707f8f29cf302 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 30 Sep 2009 15:35:01 +0200 Subject: [PATCH 045/274] Backport http://lists.mysql.com/commits/57778 2677 Vladislav Vaintroub 2008-11-04 CMakeLists.txt files cleanup - remove SAFEMALLOC and SAFE_MUTEX definitions that were present in *each* CMakeLists.txt. Instead, put them into top level CMakeLists.txt, but disable on Windows, because a) SAFEMALLOC does not add any functionality that is not already present in Debug C runtime ( and 2 safe malloc one on top of the other only unnecessarily slows down the server) b)SAFE_MUTEX does not work on Windows and have been explicitely disabled on Windows with #undef previously. Fortunately, ntdll does pretty good job identifying l problems with CRITICAL_SECTIONs. DebugBreak()s on using uninited critical section, unlocking unowned critical section) -Also, remove occationally used -D_DEBUG (added by compiler anyway) sql/udf_example.c: use unixish end of line --- CMakeLists.txt | 7 +++++++ client/CMakeLists.txt | 7 ------- dbug/CMakeLists.txt | 1 - extra/CMakeLists.txt | 2 -- libmysql/CMakeLists.txt | 2 -- libmysqld/CMakeLists.txt | 3 --- mysys/CMakeLists.txt | 2 -- regex/CMakeLists.txt | 2 -- sql/CMakeLists.txt | 4 ++-- sql/udf_example.c | 10 +++++----- storage/blackhole/CMakeLists.txt | 3 --- storage/csv/CMakeLists.txt | 2 -- storage/example/CMakeLists.txt | 2 -- storage/heap/CMakeLists.txt | 2 -- storage/innobase/CMakeLists.txt | 6 +----- storage/myisam/CMakeLists.txt | 2 -- storage/myisammrg/CMakeLists.txt | 2 -- strings/CMakeLists.txt | 3 --- tests/CMakeLists.txt | 2 -- vio/CMakeLists.txt | 2 -- 20 files changed, 15 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fba26ec1464..5f2474eaaf8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,13 @@ ADD_DEFINITIONS(-DSHAREDIR="share") # Set debug options SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DFORCE_INIT_OF_VARS") +# Do not use SAFEMALLOC for Windows builds, as Debug CRT has the same functionality +# Neither SAFE_MUTEX works on Windows and it has been explicitely undefined in +# my_pthread.h +IF(NOT WIN32) + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") +ENDIF(NOT WIN32) SET(localstatedir "C:\\mysql\\data") CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/support-files/my-huge.cnf.sh diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 176613e2dc8..28e4c354a69 100755 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -14,13 +14,6 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") -# We use the "mysqlclient" library here just as safety, in case -# any of the clients here would go beyond the client API and access the -# Thread Local Storage directly. - -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib ${CMAKE_SOURCE_DIR}/extra/yassl/include diff --git a/dbug/CMakeLists.txt b/dbug/CMakeLists.txt index 8b27f79dcf4..fabb592dccc 100755 --- a/dbug/CMakeLists.txt +++ b/dbug/CMakeLists.txt @@ -18,7 +18,6 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/dbug) SET(DBUG_SOURCES dbug.c factorial.c sanity.c) IF(NOT SOURCE_SUBLIBS) - SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) ADD_LIBRARY(dbug ${DBUG_SOURCES}) ENDIF(NOT SOURCE_SUBLIBS) diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt index 0d09e676af1..44c96ccbb86 100755 --- a/extra/CMakeLists.txt +++ b/extra/CMakeLists.txt @@ -14,8 +14,6 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index 29fe4ca33c3..805551b7ee3 100755 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -14,8 +14,6 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") # Note that we don't link with the libraries "strings" or "mysys" # here, instead we recompile the files needed and include them diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index f180c6e1921..6e1ad17b808 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -13,9 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - ADD_DEFINITIONS(-DMYSQL_SERVER -DEMBEDDED_LIBRARY -DHAVE_DLOPEN) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index f2d540d2295..aa7523aea3f 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -13,8 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - # Only the server link with this library, the client libraries and the client # executables all link with recompiles of source found in the "mysys" directory. # So we only need to create one version of this library, with the "static" diff --git a/regex/CMakeLists.txt b/regex/CMakeLists.txt index a3088c00357..a2974b45b06 100755 --- a/regex/CMakeLists.txt +++ b/regex/CMakeLists.txt @@ -13,8 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DSAFEMALLOC -DSAFE_MUTEX") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 1b7175a7b82..49ae232c31c 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -15,9 +15,9 @@ INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") SET(CMAKE_CXX_FLAGS_DEBUG - "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR /Zi") + "${CMAKE_CXX_FLAGS_DEBUG} -DUSE_SYMDIR /Zi") SET(CMAKE_C_FLAGS_DEBUG - "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR /Zi") + "${CMAKE_C_FLAGS_DEBUG} -DUSE_SYMDIR /Zi") SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /MAP /MAPINFO:EXPORTS") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include diff --git a/sql/udf_example.c b/sql/udf_example.c index 1d6a9828594..4b39a83d4ac 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -138,11 +138,11 @@ typedef long long longlong; #endif #include #include - -#ifdef _WIN32 -/* inet_aton needs winsock library */ -#pragma comment(lib, "ws2_32") -#endif + +#ifdef _WIN32 +/* inet_aton needs winsock library */ +#pragma comment(lib, "ws2_32") +#endif static pthread_mutex_t LOCK_hostname; diff --git a/storage/blackhole/CMakeLists.txt b/storage/blackhole/CMakeLists.txt index b762228d7fd..bed282ef21d 100644 --- a/storage/blackhole/CMakeLists.txt +++ b/storage/blackhole/CMakeLists.txt @@ -13,9 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") SET(BLACKHOLE_SOURCES ha_blackhole.cc ha_blackhole.h) diff --git a/storage/csv/CMakeLists.txt b/storage/csv/CMakeLists.txt index eb21a9b048c..37760588897 100644 --- a/storage/csv/CMakeLists.txt +++ b/storage/csv/CMakeLists.txt @@ -13,8 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") SET(CSV_SOURCES ha_tina.cc ha_tina.h transparent_file.cc transparent_file.h) diff --git a/storage/example/CMakeLists.txt b/storage/example/CMakeLists.txt index a328da107bd..f0b1343ab9c 100644 --- a/storage/example/CMakeLists.txt +++ b/storage/example/CMakeLists.txt @@ -13,8 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") SET(EXAMPLE_SOURCES ha_example.cc) MYSQL_STORAGE_ENGINE(EXAMPLE) diff --git a/storage/heap/CMakeLists.txt b/storage/heap/CMakeLists.txt index c2d2cd1290f..4a0fa22c8f1 100755 --- a/storage/heap/CMakeLists.txt +++ b/storage/heap/CMakeLists.txt @@ -13,8 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") SET(HEAP_SOURCES _check.c _rectest.c hp_block.c hp_clear.c hp_close.c hp_create.c diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index f4d8e7b8231..31d33f06823 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -16,11 +16,7 @@ # This is the CMakeLists for InnoDB Plugin -# TODO: remove the two FLAGS_DEBUG settings when merging into -# 6.0-based trees, like is already the case for other engines in -# those trees. -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") + INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") # Include directories under innobase diff --git a/storage/myisam/CMakeLists.txt b/storage/myisam/CMakeLists.txt index 0f070510e5c..829d89a798a 100755 --- a/storage/myisam/CMakeLists.txt +++ b/storage/myisam/CMakeLists.txt @@ -15,8 +15,6 @@ INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(MYISAM_SOURCES ft_boolean_search.c ft_nlq_search.c ft_parser.c ft_static.c ft_stem.c ha_myisam.cc diff --git a/storage/myisammrg/CMakeLists.txt b/storage/myisammrg/CMakeLists.txt index 60cfffc67ff..c545d04a780 100755 --- a/storage/myisammrg/CMakeLists.txt +++ b/storage/myisammrg/CMakeLists.txt @@ -12,8 +12,6 @@ # 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 -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") diff --git a/strings/CMakeLists.txt b/strings/CMakeLists.txt index 3d9de566670..294a129fc1b 100755 --- a/strings/CMakeLists.txt +++ b/strings/CMakeLists.txt @@ -13,9 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DSAFEMALLOC -DSAFE_MUTEX") - INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) SET(STRINGS_SOURCES bchange.c bcmp.c bfill.c bmove512.c bmove_upp.c ctype-big5.c ctype-bin.c ctype-cp932.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 270aaf53c20..0ee8769cd23 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,8 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") ADD_DEFINITIONS("-DMYSQL_CLIENT") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) diff --git a/vio/CMakeLists.txt b/vio/CMakeLists.txt index 164bcde7c4b..e1bd57d150f 100755 --- a/vio/CMakeLists.txt +++ b/vio/CMakeLists.txt @@ -13,8 +13,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DSAFEMALLOC -DSAFE_MUTEX") ADD_DEFINITIONS(-DUSE_SYMDIR) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/extra/yassl/include) From 9922788d7a79318f82d798015e0854ec243447c6 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Wed, 30 Sep 2009 15:17:15 +0100 Subject: [PATCH 046/274] Post-fix for BUG#43789 NOTE: Backporting the patch to next-mr. --- mysql-test/collections/default.experimental | 1 + mysql-test/extra/rpl_tests/rpl_not_null.test | 36 +++++++++---------- .../suite/rpl/r/rpl_not_null_innodb.result | 24 ++++++------- .../suite/rpl/r/rpl_not_null_myisam.result | 24 ++++++------- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 416bf7d9e67..dc51d0cc697 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -6,3 +6,4 @@ rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails rpl_ndb.rpl_ndb_log # Bug#38998 rpl.rpl_innodb_bug28430* @solaris # Bug#46029 rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 +rpl_ndb.rpl_ndb_extraCol* # BUG#41369 2008-12-10 alik, BUG#47741 2009-09-30 alfranio diff --git a/mysql-test/extra/rpl_tests/rpl_not_null.test b/mysql-test/extra/rpl_tests/rpl_not_null.test index 88f37f9a95e..58dbd9ce29f 100644 --- a/mysql-test/extra/rpl_tests/rpl_not_null.test +++ b/mysql-test/extra/rpl_tests/rpl_not_null.test @@ -81,13 +81,13 @@ source include/diff_tables.inc; --echo TABLES t2 and t3 must be different. connection master; -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; connection slave; -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; connection master; -SELECT * FROM t4; +SELECT * FROM t4 ORDER BY a; connection slave; -SELECT * FROM t4; +SELECT * FROM t4 ORDER BY a; --echo ************* EXECUTION WITH UPDATES and REPLACES ************* connection master; @@ -139,9 +139,9 @@ INSERT INTO t1(a) VALUES (5); --echo TABLES t1 and t2 must be different. sync_slave_with_master; connection master; -SELECT a,b+0,c+0 FROM t1; +SELECT a,b+0,c+0 FROM t1 ORDER BY a; connection slave; -SELECT a,b+0,c+0 FROM t1; +SELECT a,b+0,c+0 FROM t1 ORDER BY a; --echo ************* EXECUTION WITH UPDATES and REPLACES ************* connection master; @@ -262,17 +262,17 @@ sync_slave_with_master; # connection slave; # --source include/wait_for_slave_sql_to_stop.inc # connection master; -# SELECT * FROM t1; +# SELECT * FROM t1 ORDER BY a; # connection slave; -# SELECT * FROM t1; +# SELECT * FROM t1 ORDER BY a; # connection master; -# SELECT * FROM t2; +# SELECT * FROM t2 ORDER BY a; # connection slave; -# SELECT * FROM t2; +# SELECT * FROM t2 ORDER BY a; # connection master; -# SELECT * FROM t3; +# SELECT * FROM t3 ORDER BY a; # connection slave; -# SELECT * FROM t3; +# SELECT * FROM t3 ORDER BY a; # --source include/reset_master_and_slave.inc # # connection master; @@ -343,17 +343,17 @@ connection master; sync_slave_with_master; connection master; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; connection slave; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; connection master; -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; connection slave; -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; connection master; -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; connection slave; -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; connection master; diff --git a/mysql-test/suite/rpl/r/rpl_not_null_innodb.result b/mysql-test/suite/rpl/r/rpl_not_null_innodb.result index 7717beb0a47..b09fbab905a 100644 --- a/mysql-test/suite/rpl/r/rpl_not_null_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_not_null_innodb.result @@ -48,24 +48,24 @@ TABLES t1 and t2 must be equal otherwise an error will be thrown. Comparing tables master:test.t1 and slave:test.t1 Comparing tables master:test.t2 and slave:test.t2 TABLES t2 and t3 must be different. -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; a b 1 NULL 2 1111-11-11 3 NULL -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; a b c 1 NULL 500 2 1111-11-11 500 3 NULL 500 -SELECT * FROM t4; +SELECT * FROM t4 ORDER BY a; a b c 1 NULL 1 2 1111-11-11 2 3 NULL NULL 4 NULL 4 5 NULL NULL -SELECT * FROM t4; +SELECT * FROM t4 ORDER BY a; a b 1 NULL 2 1111-11-11 @@ -100,14 +100,14 @@ INSERT INTO t1(a,c) VALUES (4, b'01'); INSERT INTO t1(a) VALUES (5); ************* SHOWING THE RESULT SETS WITH INSERTS ************* TABLES t1 and t2 must be different. -SELECT a,b+0,c+0 FROM t1; +SELECT a,b+0,c+0 FROM t1 ORDER BY a; a b+0 c+0 1 NULL 1 2 0 1 3 NULL NULL 4 NULL 1 5 NULL NULL -SELECT a,b+0,c+0 FROM t1; +SELECT a,b+0,c+0 FROM t1 ORDER BY a; a b+0 c+0 1 NULL 1 2 0 1 @@ -163,34 +163,34 @@ REPLACE INTO t3(a, b) VALUES (5, null); REPLACE INTO t3(a, b) VALUES (3, null); UPDATE t3 SET b = NULL where a = 4; ************* SHOWING THE RESULT SETS ************* -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 NULL 2 NULL 3 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b c 1 0 0 2 0 0 3 1 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 NULL 2 NULL 3 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b c 1 0 NULL 2 0 NULL 3 1 NULL -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; a b 1 NULL 2 NULL 3 NULL 4 NULL 5 NULL -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; a b c 1 0 500 2 0 500 diff --git a/mysql-test/suite/rpl/r/rpl_not_null_myisam.result b/mysql-test/suite/rpl/r/rpl_not_null_myisam.result index 57a015367bb..09611dc6480 100644 --- a/mysql-test/suite/rpl/r/rpl_not_null_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_not_null_myisam.result @@ -48,24 +48,24 @@ TABLES t1 and t2 must be equal otherwise an error will be thrown. Comparing tables master:test.t1 and slave:test.t1 Comparing tables master:test.t2 and slave:test.t2 TABLES t2 and t3 must be different. -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; a b 1 NULL 2 1111-11-11 3 NULL -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; a b c 1 NULL 500 2 1111-11-11 500 3 NULL 500 -SELECT * FROM t4; +SELECT * FROM t4 ORDER BY a; a b c 1 NULL 1 2 1111-11-11 2 3 NULL NULL 4 NULL 4 5 NULL NULL -SELECT * FROM t4; +SELECT * FROM t4 ORDER BY a; a b 1 NULL 2 1111-11-11 @@ -100,14 +100,14 @@ INSERT INTO t1(a,c) VALUES (4, b'01'); INSERT INTO t1(a) VALUES (5); ************* SHOWING THE RESULT SETS WITH INSERTS ************* TABLES t1 and t2 must be different. -SELECT a,b+0,c+0 FROM t1; +SELECT a,b+0,c+0 FROM t1 ORDER BY a; a b+0 c+0 1 NULL 1 2 0 1 3 NULL NULL 4 NULL 1 5 NULL NULL -SELECT a,b+0,c+0 FROM t1; +SELECT a,b+0,c+0 FROM t1 ORDER BY a; a b+0 c+0 1 NULL 1 2 0 1 @@ -163,34 +163,34 @@ REPLACE INTO t3(a, b) VALUES (5, null); REPLACE INTO t3(a, b) VALUES (3, null); UPDATE t3 SET b = NULL where a = 4; ************* SHOWING THE RESULT SETS ************* -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 NULL 2 NULL 3 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b c 1 0 0 2 0 0 3 1 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 NULL 2 NULL 3 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b c 1 0 NULL 2 0 NULL 3 1 NULL -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; a b 1 NULL 2 NULL 3 NULL 4 NULL 5 NULL -SELECT * FROM t3; +SELECT * FROM t3 ORDER BY a; a b c 1 0 500 2 0 500 From 0ebecf7f0af131dfe0c046ffddc55e3767bea33a Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Wed, 30 Sep 2009 16:25:01 +0100 Subject: [PATCH 047/274] BUG#47741 rpl_ndb_extraCol fails in next-mr (mysql-5.1-rep+2) in RBR This is a temporary fix. NOTE: Backporting the patch to next-mr. --- .../extra/rpl_tests/rpl_extraSlave_Col.test | 75 ++++++++++--------- .../suite/rpl_ndb/r/rpl_ndb_extraCol.result | 56 -------------- 2 files changed, 39 insertions(+), 92 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index 1eaefa661f9..46168d6b97a 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -410,51 +410,54 @@ sync_slave_with_master; ############################################################### # Error reaction is up to sql_mode of the slave sql (bug#38173) #--echo *** Create t9 on slave *** -STOP SLAVE; -RESET SLAVE; -eval CREATE TABLE t9 (a INT KEY, b BLOB, c CHAR(5), - d TIMESTAMP, - e INT NOT NULL, - f text not null, - g text, - h blob not null, - i blob) ENGINE=$engine_type; +# Please, check BUG#47741 to see why you are not testing NDB. +if (`SELECT $engine_type != 'NDB'`) +{ + STOP SLAVE; + RESET SLAVE; + eval CREATE TABLE t9 (a INT KEY, b BLOB, c CHAR(5), + d TIMESTAMP, + e INT NOT NULL, + f text not null, + g text, + h blob not null, + i blob) ENGINE=$engine_type; ---echo *** Create t9 on Master *** -connection master; -eval CREATE TABLE t9 (a INT PRIMARY KEY, b BLOB, c CHAR(5) + --echo *** Create t9 on Master *** + connection master; + eval CREATE TABLE t9 (a INT PRIMARY KEY, b BLOB, c CHAR(5) ) ENGINE=$engine_type; -RESET MASTER; + RESET MASTER; ---echo *** Start Slave *** -connection slave; -START SLAVE; + --echo *** Start Slave *** + connection slave; + START SLAVE; ---echo *** Master Data Insert *** -connection master; -set @b1 = 'b1b1b1b1'; -set @b1 = concat(@b1,@b1); -INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA'); + --echo *** Master Data Insert *** + connection master; + set @b1 = 'b1b1b1b1'; -# the test would stop slave if @@sql_mode for the sql thread -# was set to strict. Otherwise, as with this tests setup, -# the implicit defaults will be inserted into fields even though -# they are declared without DEFAULT clause. + set @b1 = concat(@b1,@b1); + INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA'); -sync_slave_with_master; -select * from t9; + # the test would stop slave if @@sql_mode for the sql thread + # was set to strict. Otherwise, as with this tests setup, + # the implicit defaults will be inserted into fields even though + # they are declared without DEFAULT clause. -# todo: fix Bug #43992 slave sql thread can't tune own sql_mode ... -# and add/restore waiting for stop test - -#--source include/wait_for_slave_sql_to_stop.inc -#--replace_result $MASTER_MYPORT MASTER_PORT -#--replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 # -#--query_vertical SHOW SLAVE STATUS -#SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -#START SLAVE; + sync_slave_with_master; + select * from t9; + # todo: fix Bug #43992 slave sql thread can't tune own sql_mode ... + # and add/restore waiting for stop test + #--source include/wait_for_slave_sql_to_stop.inc + #--replace_result $MASTER_MYPORT MASTER_PORT + #--replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 # + #--query_vertical SHOW SLAVE STATUS + #SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; + #START SLAVE; +} #--echo *** Drop t9 *** #connection master; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result index f812509de6f..f514bf7a75b 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result @@ -400,62 +400,6 @@ set @b1 = concat(@b1,@b1); INSERT INTO t8 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA'); *** Drop t8 *** DROP TABLE t8; -STOP SLAVE; -RESET SLAVE; -CREATE TABLE t9 (a INT KEY, b BLOB, c CHAR(5), -d TIMESTAMP, -e INT NOT NULL) ENGINE='NDB'; -*** Create t9 on Master *** -CREATE TABLE t9 (a INT PRIMARY KEY, b BLOB, c CHAR(5) -) ENGINE='NDB'; -RESET MASTER; -*** Start Slave *** -START SLAVE; -*** Master Data Insert *** -set @b1 = 'b1b1b1b1'; -set @b1 = concat(@b1,@b1); -INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA'); -SHOW SLAVE STATUS; -Slave_IO_State # -Master_Host 127.0.0.1 -Master_User root -Master_Port # -Connect_Retry 1 -Master_Log_File master-bin.000001 -Read_Master_Log_Pos # -Relay_Log_File # -Relay_Log_Pos # -Relay_Master_Log_File master-bin.000001 -Slave_IO_Running Yes -Slave_SQL_Running No -Replicate_Do_DB -Replicate_Ignore_DB -Replicate_Do_Table -Replicate_Ignore_Table # -Replicate_Wild_Do_Table -Replicate_Wild_Ignore_Table -Last_Errno 1364 -Last_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 447 -Skip_Counter 0 -Exec_Master_Log_Pos # -Relay_Log_Space # -Until_Condition None -Until_Log_File -Until_Log_Pos 0 -Master_SSL_Allowed No -Master_SSL_CA_File -Master_SSL_CA_Path -Master_SSL_Cert -Master_SSL_Cipher -Master_SSL_Key -Seconds_Behind_Master # -Master_SSL_Verify_Server_Cert No -Last_IO_Errno # -Last_IO_Error # -Last_SQL_Errno 1364 -Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 447 -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; -START SLAVE; *** Create t10 on slave *** STOP SLAVE; RESET SLAVE; From 14c2cfb568e081ef66e4b6aadfc9611dd0f4be88 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 30 Sep 2009 17:40:12 +0200 Subject: [PATCH 048/274] Backport of this changeset http://lists.mysql.com/commits/59686 Cleanup pthread_self(), pthread_create(), pthread_join() implementation on Windows. Prior implementation is was unnecessarily complicated and even differs in embedded and non-embedded case. Improvements in this patch: * pthread_t is now the unique thread ID, instead of HANDLE returned by beginthread This simplifies pthread_self() to be just straight GetCurrentThreadId(). prior it was much art involved in passing the beginthread() handle from the caller to the TLS structure in the child thread ( did not work for the main thread of course) * remove MySQL specific my_thread_init()/my_thread_end() from pthread_create. No automagic is done on Unix on pthread_create(). Having the same on Windows will improve portability and avoid extra #ifdef's * remove redefinition of getpid() - it was defined as GetCurrentThreadId() --- include/config-win.h | 3 + include/my_pthread.h | 12 ++-- libmysqld/CMakeLists.txt | 2 +- mysys/my_thr_init.c | 43 ++++++++++--- mysys/my_wincond.c | 3 +- mysys/my_winthread.c | 131 +++++++++++++++++++-------------------- sql/mysqld.cc | 62 +++++++----------- sql/sql_connect.cc | 9 --- sql/sql_insert.cc | 5 -- 9 files changed, 131 insertions(+), 139 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index bcad4e04346..514a762d6d8 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -27,6 +27,9 @@ #include #include #include +#include +#include /* getpid()*/ + #define HAVE_SMEM 1 diff --git a/include/my_pthread.h b/include/my_pthread.h index 2928cb60c2d..b4fe1203d2b 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -31,7 +31,7 @@ extern "C" { #if defined(__WIN__) typedef CRITICAL_SECTION pthread_mutex_t; -typedef HANDLE pthread_t; +typedef DWORD pthread_t; typedef struct thread_attr { DWORD dwStackSize ; DWORD dwCreatingFlag ; @@ -64,8 +64,7 @@ typedef struct { typedef int pthread_mutexattr_t; -#define win_pthread_self my_thread_var->pthread_self -#define pthread_self() win_pthread_self +#define pthread_self() GetCurrentThreadId() #define pthread_handler_t EXTERNC void * __cdecl typedef void * (__cdecl *pthread_handler)(void *); @@ -99,7 +98,7 @@ struct timespec { (ABSTIME).max_timeout_msec= (long)((NSEC)/1000000); \ } -void win_pthread_init(void); + int win_pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *); int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); @@ -116,11 +115,11 @@ int pthread_attr_destroy(pthread_attr_t *connect_att); struct tm *localtime_r(const time_t *timep,struct tm *tmp); struct tm *gmtime_r(const time_t *timep,struct tm *tmp); +void pthread_exit(void *a); +int pthread_join(pthread_t thread, void **value_ptr); -void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #define ETIMEDOUT 145 /* Win32 doesn't have this */ -#define getpid() GetCurrentThreadId() #define HAVE_LOCALTIME_R 1 #define _REENTRANT 1 #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 @@ -145,7 +144,6 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B)) #define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) -#define pthread_join(A,B) (WaitForSingleObject((A), INFINITE) != WAIT_OBJECT_0) /* Dummy defines for easier code */ #define pthread_attr_setdetachstate(A,B) pthread_dummy(0) diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 6e1ad17b808..bce14b38338 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -130,7 +130,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc ../sql/partition_info.cc ../sql/sql_connect.cc ../sql/scheduler.cc ../sql/event_parse_data.cc - ./sql/sql_signal.cc + ../sql/sql_signal.cc ${GEN_SOURCES} ${LIB_SOURCES}) diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 2c346145cf5..c59b2d51742 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -42,7 +42,9 @@ pthread_mutexattr_t my_fast_mutexattr; #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP pthread_mutexattr_t my_errorcheck_mutexattr; #endif - +#ifdef _MSC_VER +static void install_sigabrt_handler(); +#endif #ifdef TARGET_OS_LINUX /* @@ -145,15 +147,18 @@ my_bool my_thread_global_init(void) pthread_mutex_init(&THR_LOCK_threads,MY_MUTEX_INIT_FAST); pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST); pthread_cond_init(&THR_COND_threads, NULL); -#if defined( __WIN__) || defined(OS2) - win_pthread_init(); -#endif + #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW); #endif #ifndef HAVE_GETHOSTBYNAME_R pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW); #endif + +#ifdef _MSC_VER + install_sigabrt_handler(); +#endif + if (my_thread_init()) { my_thread_global_end(); /* Clean up */ @@ -268,11 +273,7 @@ my_bool my_thread_init(void) goto end; } pthread_setspecific(THR_KEY_mysys,tmp); -#if defined(__WIN__) && defined(EMBEDDED_LIBRARY) - tmp->pthread_self= (pthread_t) getpid(); -#else tmp->pthread_self= pthread_self(); -#endif pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST); pthread_cond_init(&tmp->suspend, NULL); tmp->init= 1; @@ -398,4 +399,30 @@ static uint get_thread_lib(void) return THD_LIB_OTHER; } +#ifdef _WIN32 +/* + In Visual Studio 2005 and later, default SIGABRT handler will overwrite + any unhandled exception filter set by the application and will try to + call JIT debugger. This is not what we want, this we calling __debugbreak + to stop in debugger, if process is being debugged or to generate + EXCEPTION_BREAKPOINT and then handle_segfault will do its magic. +*/ + +#if (_MSC_VER >= 1400) +static void my_sigabrt_handler(int sig) +{ + __debugbreak(); +} +#endif /*_MSC_VER >=1400 */ + +static void install_sigabrt_handler(void) +{ +#if (_MSC_VER >=1400) + /*abort() should not override our exception filter*/ + _set_abort_behavior(0,_CALL_REPORTFAULT); + signal(SIGABRT,my_sigabrt_handler); +#endif /* _MSC_VER >=1400 */ +} +#endif + #endif /* THREAD */ diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c index d1b07b61408..956d29a970b 100644 --- a/mysys/my_wincond.c +++ b/mysys/my_wincond.c @@ -16,12 +16,11 @@ /***************************************************************************** ** The following is a simple implementation of posix conditions *****************************************************************************/ +#if defined(_WIN32) #undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */ #include "mysys_priv.h" -#if defined(THREAD) && defined(__WIN__) #include -#undef getpid #include #include diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c index 543e1787fb6..9e8458b0799 100644 --- a/mysys/my_winthread.c +++ b/mysys/my_winthread.c @@ -14,33 +14,23 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /***************************************************************************** -** Simulation of posix threads calls for WIN95 and NT +** Simulation of posix threads calls for Windows *****************************************************************************/ - +#if defined (_WIN32) /* SAFE_MUTEX will not work until the thread structure is up to date */ #undef SAFE_MUTEX - #include "mysys_priv.h" -#if defined(THREAD) && defined(__WIN__) -#include -#undef getpid #include +#include -static pthread_mutex_t THR_LOCK_thread; +static void install_sigabrt_handler(void); -struct pthread_map +struct thread_start_parameter { - HANDLE pthreadself; pthread_handler func; - void *param; + void *arg; }; -void win_pthread_init(void) -{ - pthread_mutex_init(&THR_LOCK_thread,MY_MUTEX_INIT_FAST); -} - - /** Adapter to @c pthread_mutex_trylock() @@ -62,72 +52,81 @@ win_pthread_mutex_trylock(pthread_mutex_t *mutex) return EBUSY; } - -/* -** We have tried to use '_beginthreadex' instead of '_beginthread' here -** but in this case the program leaks about 512 characters for each -** created thread ! -** As we want to save the created thread handler for other threads to -** use and to be returned by pthread_self() (instead of the Win32 pseudo -** handler), we have to go trough pthread_start() to catch the returned handler -** in the new thread. -*/ - -pthread_handler_t pthread_start(void *param) +static unsigned int __stdcall pthread_start(void *p) { - pthread_handler func=((struct pthread_map *) param)->func; - void *func_param=((struct pthread_map *) param)->param; - my_thread_init(); /* Will always succeed in windows */ - pthread_mutex_lock(&THR_LOCK_thread); /* Wait for beginthread to return */ - win_pthread_self=((struct pthread_map *) param)->pthreadself; - pthread_mutex_unlock(&THR_LOCK_thread); - free((char*) param); /* Free param from create */ - pthread_exit((void*) (*func)(func_param)); - return 0; /* Safety */ + struct thread_start_parameter *par= (struct thread_start_parameter *)p; + pthread_handler func= par->func; + void *arg= par->arg; + free(p); + (*func)(arg); + return 0; } int pthread_create(pthread_t *thread_id, pthread_attr_t *attr, - pthread_handler func, void *param) + pthread_handler func, void *param) { - HANDLE hThread; - struct pthread_map *map; + uintptr_t handle; + struct thread_start_parameter *par; + unsigned int stack_size; DBUG_ENTER("pthread_create"); - if (!(map=malloc(sizeof(*map)))) - DBUG_RETURN(-1); - map->func=func; - map->param=param; - pthread_mutex_lock(&THR_LOCK_thread); -#ifdef __BORLANDC__ - hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start, - attr->dwStackSize ? attr->dwStackSize : - 65535, (void*) map); -#else - hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start, - attr->dwStackSize ? attr->dwStackSize : - 65535, (void*) map); -#endif - DBUG_PRINT("info", ("hThread=%lu",(long) hThread)); - *thread_id=map->pthreadself=hThread; - pthread_mutex_unlock(&THR_LOCK_thread); + par= (struct thread_start_parameter *)malloc(sizeof(*par)); + if (!par) + goto error_return; - if (hThread == (HANDLE) -1) - { - int error=errno; - DBUG_PRINT("error", - ("Can't create thread to handle request (error %d)",error)); - DBUG_RETURN(error ? error : -1); - } - VOID(SetThreadPriority(hThread, attr->priority)) ; + par->func= func; + par->arg= param; + stack_size= attr?attr->dwStackSize:0; + + handle= _beginthreadex(NULL, stack_size , pthread_start, par, 0, thread_id); + if (!handle) + goto error_return; + DBUG_PRINT("info", ("thread id=%u",*thread_id)); + + /* Do not need thread handle, close it */ + CloseHandle((HANDLE)handle); DBUG_RETURN(0); + +error_return: + DBUG_PRINT("error", + ("Can't create thread to handle request (error %d)",errno)); + DBUG_RETURN(-1); } void pthread_exit(void *a) { - _endthread(); + _endthreadex(0); } +int pthread_join(pthread_t thread, void **value_ptr) +{ + DWORD ret; + HANDLE handle; + + handle= OpenThread(SYNCHRONIZE, FALSE, thread); + if (!handle) + { + errno= EINVAL; + goto error_return; + } + + ret= WaitForSingleObject(handle, INFINITE); + + if(ret != WAIT_OBJECT_0) + { + errno= EINVAL; + goto error_return; + } + + CloseHandle(handle); + return 0; + +error_return: + if(handle) + CloseHandle(handle); + return -1; +} #endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index bb79f931fb3..3585539318d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -805,7 +805,10 @@ static void set_server_version(void); static int init_thread_environment(); static char *get_relative_path(const char *path); static int fix_paths(void); -pthread_handler_t handle_connections_sockets(void *arg); +void handle_connections_sockets(); +#ifdef _WIN32 +pthread_handler_t handle_connections_sockets_thread(void *arg); +#endif pthread_handler_t kill_server_thread(void *arg); static void bootstrap(FILE *file); static bool read_init_file(char *file_name); @@ -2034,29 +2037,7 @@ static BOOL WINAPI console_event_handler( DWORD type ) } -/* - In Visual Studio 2005 and later, default SIGABRT handler will overwrite - any unhandled exception filter set by the application and will try to - call JIT debugger. This is not what we want, this we calling __debugbreak - to stop in debugger, if process is being debugged or to generate - EXCEPTION_BREAKPOINT and then handle_segfault will do its magic. -*/ -#if (_MSC_VER >= 1400) -static void my_sigabrt_handler(int sig) -{ - __debugbreak(); -} -#endif /*_MSC_VER >=1400 */ - -void win_install_sigabrt_handler(void) -{ -#if (_MSC_VER >=1400) - /*abort() should not override our exception filter*/ - _set_abort_behavior(0,_CALL_REPORTFAULT); - signal(SIGABRT,my_sigabrt_handler); -#endif /* _MSC_VER >=1400 */ -} #ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER #define DEBUGGER_ATTACH_TIMEOUT 120 @@ -2135,7 +2116,6 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) static void init_signals(void) { - win_install_sigabrt_handler(); if(opt_console) SetConsoleCtrlHandler(console_event_handler,TRUE); @@ -4132,7 +4112,8 @@ static void create_shutdown_thread() #ifdef __WIN__ hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name); pthread_t hThread; - if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0)) + if (pthread_create(&hThread,&connection_attrib, + handle_connections_sockets_thread, 0)) sql_print_warning("Can't create thread to handle shutdown requests"); // On "Stop Service" we have to do regular shutdown @@ -4177,7 +4158,7 @@ static void handle_connections_methods() { handler_count++; if (pthread_create(&hThread,&connection_attrib, - handle_connections_sockets, 0)) + handle_connections_sockets_thread, 0)) { sql_print_warning("Can't create thread to handle TCP/IP"); handler_count--; @@ -4506,18 +4487,11 @@ we force server id to 2, but this MySQL server will not act as a slave."); pthread_cond_signal(&COND_server_started); pthread_mutex_unlock(&LOCK_server_started); -#if defined(__NT__) || defined(HAVE_SMEM) +#if defined(_WIN32) || defined(HAVE_SMEM) handle_connections_methods(); #else -#ifdef __WIN__ - if (!have_tcpip || opt_disable_networking) - { - sql_print_error("TCP/IP unavailable or disabled with --skip-networking; no available interfaces"); - unireg_abort(1); - } -#endif - handle_connections_sockets(0); -#endif /* __NT__ */ + handle_connections_sockets(); +#endif /* _WIN32 || HAVE_SMEM */ /* (void) pthread_attr_destroy(&connection_attrib); */ @@ -4992,7 +4966,7 @@ inline void kill_broken_server() /* Handle new connections and spawn new process to handle them */ #ifndef EMBEDDED_LIBRARY -pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) +void handle_connections_sockets() { my_socket sock,new_sock; uint error_count=0; @@ -5195,13 +5169,19 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) create_new_thread(thd); } - - decrement_handler_count(); - DBUG_RETURN(0); + DBUG_VOID_RETURN; } -#ifdef __NT__ +#ifdef _WIN32 +pthread_handler_t handle_connections_sockets_thread(void *arg) +{ + my_thread_init(); + handle_connections_sockets(); + decrement_handler_count(); + return 0; +} + pthread_handler_t handle_connections_namedpipes(void *arg) { HANDLE hConnectedPipe; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 404d734559f..a87d201d9ed 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -39,10 +39,6 @@ #define MIN_HANDSHAKE_SIZE 6 #endif /* HAVE_OPENSSL */ -#ifdef __WIN__ -extern void win_install_sigabrt_handler(); -#endif - /* Get structure for logging connection data for the current user */ @@ -612,13 +608,8 @@ void thd_init_client_charset(THD *thd, uint cs_number) bool init_new_connection_handler_thread() { pthread_detach_this_thread(); -#if defined(__WIN__) - win_install_sigabrt_handler(); -#else - /* Win32 calls this in pthread_create */ if (my_thread_init()) return 1; -#endif /* __WIN__ */ return 0; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7d2513bd419..1ef4d5827ec 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2498,7 +2498,6 @@ pthread_handler_t handle_delayed_insert(void *arg) since it does not find one in the list. */ pthread_mutex_lock(&di->mutex); -#if !defined( __WIN__) /* Win32 calls this in pthread_create */ if (my_thread_init()) { /* Can't use my_error since store_globals has not yet been called */ @@ -2506,13 +2505,9 @@ pthread_handler_t handle_delayed_insert(void *arg) ER(ER_OUT_OF_RESOURCES), NULL); goto end; } -#endif - handle_delayed_insert_impl(thd, di); -#ifndef __WIN__ end: -#endif /* di should be unlinked from the thread handler list and have no active clients From 8f43e00841d141ceae42ff9e83a9f5f4eeb298e3 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 30 Sep 2009 17:42:25 +0100 Subject: [PATCH 049/274] BUG#47749: rpl_slave_skip fails sporadically on PB2 (mysql-5.1-rep+2 tree). rpl_slave_skip fails randomly on PB2. This patch fixes the failure by setting explicit wait for SQL thread to stop, instead of the wait_for_slave_to_stop mysqltest command, after a start until command is executed. --- mysql-test/suite/rpl/t/rpl_slave_skip.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip.test b/mysql-test/suite/rpl/t/rpl_slave_skip.test index f4cb0f69e93..6336e775af1 100644 --- a/mysql-test/suite/rpl/t/rpl_slave_skip.test +++ b/mysql-test/suite/rpl/t/rpl_slave_skip.test @@ -27,7 +27,7 @@ connection slave; # Stop when reaching the the first table map event. START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=762; -wait_for_slave_to_stop; +-- source include/wait_for_slave_sql_to_stop.inc --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 8 # 9 # 23 # 33 # 35 # 36 # query_vertical SHOW SLAVE STATUS; @@ -59,7 +59,7 @@ source include/show_binlog_events.inc; connection slave; START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=106; -wait_for_slave_to_stop; +-- source include/wait_for_slave_sql_to_stop.inc SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; sync_with_master; From 4acaca0202ccf1beb553a670121a25b15965be59 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 30 Sep 2009 22:10:22 +0200 Subject: [PATCH 050/274] backport of Revision: 2597.72.1 revid:sp1r-Reggie@core.-20080403153947-15243 removed instances of __NT__ from code. We now only build "NT" binaries --- CMakeLists.txt | 3 --- include/config-win.h | 9 ++------- include/my_sys.h | 2 +- mysys/my_delete.c | 2 +- mysys/my_thr_init.c | 5 +++++ mysys/my_winfile.c | 15 ++++++++------- sql/log.cc | 14 +++++++------- sql/mysqld.cc | 20 ++++++++------------ sql/set_var.cc | 2 +- sql/sql_connect.cc | 2 +- vio/viosocket.c | 4 ++-- 11 files changed, 36 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f2474eaaf8..301855cf326 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,9 +62,6 @@ CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/support-files/my-medium.cnf.sh CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/support-files/my-small.cnf.sh ${CMAKE_SOURCE_DIR}/support-files/my-small.ini @ONLY) - -ADD_DEFINITIONS(-D__NT__) - IF(CYBOZU) ADD_DEFINITIONS(-DCYBOZU) ENDIF(CYBOZU) diff --git a/include/config-win.h b/include/config-win.h index 514a762d6d8..725b4fdf07b 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -177,7 +177,7 @@ typedef uint rf_SetTimer; #define SIZEOF_CHARP 4 #endif #define HAVE_BROKEN_NETINET_INCLUDES -#ifdef __NT__ +#ifdef _WIN32 #define HAVE_NAMED_PIPE /* We can only create pipes on NT */ #endif @@ -290,11 +290,6 @@ inline ulonglong double2ulonglong(double d) #define strcasecmp stricmp #define strncasecmp strnicmp -#ifndef __NT__ -#undef FILE_SHARE_DELETE -#define FILE_SHARE_DELETE 0 /* Not implemented on Win 98/ME */ -#endif - #ifdef NOT_USED #define HAVE_SNPRINTF /* Gave link error */ #define _snprintf snprintf @@ -344,7 +339,7 @@ inline ulonglong double2ulonglong(double d) #define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V)) #define thread_safe_decrement(V,L) InterlockedDecrement((long*) &(V)) /* The following is only used for statistics, so it should be good enough */ -#ifdef __NT__ /* This should also work on Win98 but .. */ +#ifdef _WIN32 #define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C)) #define thread_safe_sub(V,C,L) InterlockedExchangeAdd((long*) &(V),-(long) (C)) #endif diff --git a/include/my_sys.h b/include/my_sys.h index 451c8418ebd..4b93dc0e364 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -640,7 +640,7 @@ extern int my_access(const char *path, int amode); extern int check_if_legal_filename(const char *path); extern int check_if_legal_tablename(const char *path); -#if defined(__WIN__) && defined(__NT__) +#ifdef _WIN32 extern int nt_share_delete(const char *name,myf MyFlags); #define my_delete_allow_opened(fname,flags) nt_share_delete((fname),(flags)) #else diff --git a/mysys/my_delete.c b/mysys/my_delete.c index 22425ed95fd..3ab6ba399f9 100644 --- a/mysys/my_delete.c +++ b/mysys/my_delete.c @@ -36,7 +36,7 @@ int my_delete(const char *name, myf MyFlags) DBUG_RETURN(err); } /* my_delete */ -#if defined(__WIN__) && defined(__NT__) +#if defined(__WIN__) /* Delete file which is possibly not closed. diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index c59b2d51742..c6057f19a82 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -267,6 +267,11 @@ my_bool my_thread_init(void) #endif goto end; } + +#ifdef _MSC_VER + install_sigabrt_handler(); +#endif + if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp)))) { error= 1; diff --git a/mysys/my_winfile.c b/mysys/my_winfile.c index de1d747c967..6a2cda5ba29 100644 --- a/mysys/my_winfile.c +++ b/mysys/my_winfile.c @@ -314,10 +314,10 @@ size_t my_win_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset) if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, &ov)) { DWORD lastError= GetLastError(); - /* - ERROR_BROKEN_PIPE is returned when no more data coming - through e.g. a command pipe in windows : see MSDN on ReadFile. - */ + /* + ERROR_BROKEN_PIPE is returned when no more data coming + through e.g. a command pipe in windows : see MSDN on ReadFile. + */ if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE) DBUG_RETURN(0); /*return 0 at EOF*/ my_osmaperr(lastError); @@ -367,8 +367,8 @@ size_t my_win_pwrite(File Filedes, const uchar *Buffer, size_t Count, LARGE_INTEGER li; DBUG_ENTER("my_win_pwrite"); - DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count: %zd, offset: %llu", - Filedes, Buffer, Count, (ulonglong)offset)); + DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count: %llu, offset: %llu", + Filedes, Buffer, (ulonglong)Count, (ulonglong)offset)); if(!Count) DBUG_RETURN(0); @@ -425,7 +425,8 @@ size_t my_win_write(File fd, const uchar *Buffer, size_t Count) HANDLE hFile; DBUG_ENTER("my_win_write"); - DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count %zd", fd, Buffer, Count)); + DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count %llu", fd, Buffer, + (ulonglong)Count)); if(my_get_open_flags(fd) & _O_APPEND) { /* diff --git a/sql/log.cc b/sql/log.cc index 3d4aca572f0..ed208a84ffc 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -33,7 +33,7 @@ #include #include // For test_if_number -#ifdef __NT__ +#ifdef _WIN32 #include "message.h" #endif @@ -1794,7 +1794,7 @@ err: DBUG_RETURN(-1); } -#ifdef __NT__ +#ifdef _WIN32 static int eventSource = 0; static void setup_windows_event_source() @@ -1829,7 +1829,7 @@ static void setup_windows_event_source() RegCloseKey(hRegKey); } -#endif /* __NT__ */ +#endif /* _WIN32 */ /** @@ -1960,7 +1960,7 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, #ifdef EMBEDDED_LIBRARY "embedded library\n", my_progname, server_version, MYSQL_COMPILATION_COMMENT -#elif __NT__ +#elif _WIN32 "started with:\nTCP Port: %d, Named Pipe: %s\n", my_progname, server_version, MYSQL_COMPILATION_COMMENT, mysqld_port, mysqld_unix_port @@ -4851,7 +4851,7 @@ void MYSQL_BIN_LOG::signal_update() DBUG_VOID_RETURN; } -#ifdef __NT__ +#ifdef _WIN32 static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, size_t length, size_t buffLen) { @@ -4884,7 +4884,7 @@ static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, DBUG_VOID_RETURN; } -#endif /* __NT__ */ +#endif /* _WIN32 */ /** @@ -4946,7 +4946,7 @@ int vprint_msg_to_log(enum loglevel level, const char *format, va_list args) length= my_vsnprintf(buff, sizeof(buff), format, args); print_buffer_to_file(level, buff); -#ifdef __NT__ +#ifdef _WIN32 print_buffer_to_nt_eventlog(level, buff, length, sizeof(buff)); #endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3585539318d..e2d4de4dc56 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -732,7 +732,7 @@ static NTService Service; ///< Service object for WinNT #endif /* EMBEDDED_LIBRARY */ #endif /* __WIN__ */ -#ifdef __NT__ +#ifdef _WIN32 static char pipe_name[512]; static SECURITY_ATTRIBUTES saPipeSecurity; static SECURITY_DESCRIPTOR sdPipeDescriptor; @@ -812,7 +812,7 @@ pthread_handler_t handle_connections_sockets_thread(void *arg); pthread_handler_t kill_server_thread(void *arg); static void bootstrap(FILE *file); static bool read_init_file(char *file_name); -#ifdef __NT__ +#ifdef _WIN32 pthread_handler_t handle_connections_namedpipes(void *arg); #endif #ifdef HAVE_SMEM @@ -898,7 +898,7 @@ static void close_connections(void) ip_sock= INVALID_SOCKET; } } -#ifdef __NT__ +#ifdef _WIN32 if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe) { HANDLE temp; @@ -1690,7 +1690,7 @@ static void network_init(void) } } -#ifdef __NT__ +#ifdef _WIN32 /* create named pipe */ if (Service.IsNT() && mysqld_unix_port[0] && !opt_bootstrap && opt_enable_named_pipe) @@ -4124,12 +4124,11 @@ static void create_shutdown_thread() #endif /* EMBEDDED_LIBRARY */ -#if (defined(__NT__) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) +#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY) static void handle_connections_methods() { pthread_t hThread; DBUG_ENTER("handle_connections_methods"); -#ifdef __NT__ if (hPipe == INVALID_HANDLE_VALUE && (!have_tcpip || opt_disable_networking) && !opt_enable_shared_memory) @@ -4137,12 +4136,10 @@ static void handle_connections_methods() sql_print_error("TCP/IP, --shared-memory, or --named-pipe should be configured on NT OS"); unireg_abort(1); // Will not return } -#endif pthread_mutex_lock(&LOCK_thread_count); (void) pthread_cond_init(&COND_handler_count,NULL); handler_count=0; -#ifdef __NT__ if (hPipe != INVALID_HANDLE_VALUE) { handler_count++; @@ -4153,7 +4150,6 @@ static void handle_connections_methods() handler_count--; } } -#endif /* __NT__ */ if (have_tcpip && !opt_disable_networking) { handler_count++; @@ -4193,7 +4189,7 @@ void decrement_handler_count() } #else #define decrement_handler_count() -#endif /* defined(__NT__) || defined(HAVE_SMEM) */ +#endif /* defined(_WIN32) || defined(HAVE_SMEM) */ #ifndef EMBEDDED_LIBRARY @@ -5261,7 +5257,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) decrement_handler_count(); DBUG_RETURN(0); } -#endif /* __NT__ */ +#endif /* _WIN32 */ #ifdef HAVE_SMEM @@ -5837,7 +5833,7 @@ struct my_option my_long_options[] = "Deprecated option, use --external-locking instead.", (uchar**) &opt_external_locking, (uchar**) &opt_external_locking, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef __NT__ +#ifdef _WIN32 {"enable-named-pipe", OPT_HAVE_NAMED_PIPE, "Enable the named pipe (NT).", (uchar**) &opt_enable_named_pipe, (uchar**) &opt_enable_named_pipe, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/sql/set_var.cc b/sql/set_var.cc index dc966c306a5..2e2bb369af1 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -434,7 +434,7 @@ static sys_var_thd_enum sys_myisam_stats_method(&vars, "myisam_stats_met &myisam_stats_method_typelib, NULL); -#ifdef __NT__ +#ifdef _WIN32 /* purecov: begin inspected */ static sys_var_const sys_named_pipe(&vars, "named_pipe", OPT_GLOBAL, SHOW_MY_BOOL, diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index a87d201d9ed..4ae267a880c 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -949,7 +949,7 @@ static bool login_connection(THD *thd) if (error) { // Wrong permissions -#ifdef __NT__ +#ifdef _WIN32 if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) my_sleep(1000); /* must wait after eof() */ #endif diff --git a/vio/viosocket.c b/vio/viosocket.c index 2d7fd0e08cd..2a22f8c7c15 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -264,7 +264,7 @@ int vio_close(Vio * vio) #ifdef __WIN__ if (vio->type == VIO_TYPE_NAMEDPIPE) { -#if defined(__NT__) && defined(MYSQL_SERVER) +#if defined(MYSQL_SERVER) CancelIo(vio->hPipe); DisconnectNamedPipe(vio->hPipe); #endif @@ -450,7 +450,7 @@ int vio_close_pipe(Vio * vio) { int r; DBUG_ENTER("vio_close_pipe"); -#if defined(__NT__) && defined(MYSQL_SERVER) +#if defined(MYSQL_SERVER) CancelIo(vio->hPipe); DisconnectNamedPipe(vio->hPipe); #endif From 5c25d17c4e63325048340a76eb8d2fdf6ae475f4 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Wed, 30 Sep 2009 22:41:05 +0100 Subject: [PATCH 051/274] BUG#43075 rpl.rpl_sync fails sporadically on pushbuild NOTE: Backporting the patch to next-mr. The slave was crashing while failing to execute the init_slave() function. The issue stems from two different reasons: 1 - A failure while allocating the master info structure generated a segfault due to a NULL pointer. 2 - A failure while recovering generated a segfault due to a non-initialized relay log file. In other words, the mi->init and rli->init were both set to true before executing the recovery process thus creating an inconsistent state as the relay log file was not initialized. To circumvent such problems, we refactored the recovery process which is now executed while initializing the relay log. It is ensured that the master info structure is created before accessing it and any error is propagated thus avoiding to set mi->init and rli->init to true when for instance the relay log is not initialized or the relay info is not flushed. The changes related to the refactory are described below: 1 - Removed call to init_recovery from init_slave. 2 - Changed the signature of the function init_recovery. 3 - Removed flushes. They are called while initializing the relay log and master info. 4 - Made sure that if the relay info is not flushed the mi-init and rli-init are not set to true. In this patch, we also replaced the exit(1) in the fault injection by DBUG_ABORT() to make it compliant with the code guidelines. --- sql/rpl_mi.cc | 1 + sql/rpl_rli.cc | 12 ++++++++---- sql/slave.cc | 31 ++----------------------------- sql/slave.h | 1 + 4 files changed, 12 insertions(+), 33 deletions(-) diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index cec2eabdd20..fe005bdb2a3 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -310,6 +310,7 @@ file '%s')", fname); goto err; mi->inited = 1; + mi->rli.is_relay_log_recovery= FALSE; // now change cache READ -> WRITE - must do this before flush_master_info reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1); if ((error=test(flush_master_info(mi, 1)))) diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 3a12164a1cf..b3a1bbc31d2 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -259,8 +259,10 @@ Failed to open the existing relay log info file '%s' (errno %d)", rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos; rli->group_master_log_pos= master_log_pos; - if (!rli->is_relay_log_recovery && - init_relay_log_pos(rli, + if (rli->is_relay_log_recovery && init_recovery(rli->mi, &msg)) + goto err; + + if (init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos, 0 /* no data lock*/, @@ -275,7 +277,6 @@ Failed to open the existing relay log info file '%s' (errno %d)", } #ifndef DBUG_OFF - if (!rli->is_relay_log_recovery) { char llbuf1[22], llbuf2[22]; DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s", @@ -292,7 +293,10 @@ Failed to open the existing relay log info file '%s' (errno %d)", */ reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1); if ((error= flush_relay_log_info(rli))) - sql_print_error("Failed to flush relay log info file"); + { + msg= "Failed to flush relay log info file"; + goto err; + } if (count_relay_log_space(rli)) { msg="Error counting relay log space"; diff --git a/sql/slave.cc b/sql/slave.cc index 5edb47df8b5..a1097d67052 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -129,7 +129,6 @@ static bool wait_for_relay_log_space(Relay_log_info* rli); static inline bool io_slave_killed(THD* thd,Master_info* mi); static inline bool sql_slave_killed(THD* thd,Relay_log_info* rli); static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type); -static int init_recovery(Master_info* mi); static void print_slave_skip_errors(void); static int safe_connect(THD* thd, MYSQL* mysql, Master_info* mi); static int safe_reconnect(THD* thd, MYSQL* mysql, Master_info* mi, @@ -264,12 +263,6 @@ int init_slave() goto err; } - if (active_mi->rli.is_relay_log_recovery && init_recovery(active_mi)) - { - error= 1; - goto err; - } - if (server_id && !master_host && active_mi->host[0]) master_host= active_mi->host; @@ -291,7 +284,6 @@ int init_slave() } err: - active_mi->rli.is_relay_log_recovery= FALSE; pthread_mutex_unlock(&LOCK_active_mi); DBUG_RETURN(error); } @@ -323,9 +315,8 @@ err: If there is an error, it returns (1), otherwise returns (0). */ -static int init_recovery(Master_info* mi) +int init_recovery(Master_info* mi, const char** errmsg) { - const char *errmsg= 0; DBUG_ENTER("init_recovery"); Relay_log_info *rli= &mi->rli; @@ -345,26 +336,8 @@ static int init_recovery(Master_info* mi) sizeof(mi->rli.event_relay_log_name)-1); rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE; - - if (init_relay_log_pos(rli, - rli->group_relay_log_name, - rli->group_relay_log_pos, - 0 /*no data lock*/, - &errmsg, 0)) - DBUG_RETURN(1); - - if (flush_master_info(mi, 0)) - { - sql_print_error("Failed to flush master info file"); - DBUG_RETURN(1); - } - if (flush_relay_log_info(rli)) - { - sql_print_error("Failed to flush relay info file"); - DBUG_RETURN(1); - } } - + DBUG_RETURN(0); } diff --git a/sql/slave.h b/sql/slave.h index a44a7eed83e..86b28931f21 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -134,6 +134,7 @@ extern ulonglong relay_log_space_limit; #define SLAVE_FORCE_ALL 4 int init_slave(); +int init_recovery(Master_info* mi, const char** errmsg); void init_slave_skip_errors(const char* arg); bool flush_relay_log_info(Relay_log_info* rli); int register_slave_on_master(MYSQL* mysql); From a367c88c9eef26242756efa4026962c71c5429a9 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 1 Oct 2009 00:32:15 +0100 Subject: [PATCH 052/274] Partial backport for BUG#41399, more precisely, the changes to wait_until_disconnected.inc. --- mysql-test/include/wait_until_disconnected.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/include/wait_until_disconnected.inc b/mysql-test/include/wait_until_disconnected.inc index a4362e52d01..8a989becc18 100644 --- a/mysql-test/include/wait_until_disconnected.inc +++ b/mysql-test/include/wait_until_disconnected.inc @@ -7,7 +7,7 @@ let $counter= 500; let $mysql_errno= 0; while (!$mysql_errno) { - --error 0,1053,2002,2006,2013 + --error 0,1040,1053,2002,2003,2006,2013 show status; dec $counter; From 78c65d561cc3f215e237a04484ece0a5229fb410 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 1 Oct 2009 12:22:31 +0500 Subject: [PATCH 053/274] After-fix for back-port of WL#3759. --- strings/ctype-sjis.c | 4 ++-- strings/ctype-utf8.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index ac426e0d7b5..60280efe087 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -4672,7 +4672,7 @@ static MY_CHARSET_HANDLER my_charset_handler= CHARSET_INFO my_charset_sjis_japanese_ci= { 13,0,0, /* number */ - MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM, /* state */ + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM|MY_CS_NONASCII, /* state */ "sjis", /* cs name */ "sjis_japanese_ci", /* name */ "", /* comment */ @@ -4704,7 +4704,7 @@ CHARSET_INFO my_charset_sjis_japanese_ci= CHARSET_INFO my_charset_sjis_bin= { 88,0,0, /* number */ - MY_CS_COMPILED|MY_CS_BINSORT, /* state */ + MY_CS_COMPILED|MY_CS_BINSORT|MY_CS_NONASCII, /* state */ "sjis", /* cs name */ "sjis_bin", /* name */ "", /* comment */ diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index ae942b59caa..91f633e45ce 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -4200,7 +4200,7 @@ static MY_CHARSET_HANDLER my_charset_filename_handler= CHARSET_INFO my_charset_filename= { 17,0,0, /* number */ - MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_HIDDEN, + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_HIDDEN|MY_CS_NONASCII, "filename", /* cs name */ "filename", /* name */ "", /* comment */ From dc97402c11e7b19d1358772e94d34ce5b4496fc6 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 1 Oct 2009 15:04:42 +0200 Subject: [PATCH 054/274] Changed all no_ to num_ to avoid strange names like no_list_values which is not expected to be number of list values, rather a boolea indicating no list values --- mysql-test/r/partition_column.result | 29 ++ mysql-test/t/partition_column.test | 32 ++ sql/ha_partition.cc | 134 ++++---- sql/ha_partition.h | 6 +- sql/opt_range.cc | 20 +- sql/partition_info.cc | 145 ++++----- sql/partition_info.h | 32 +- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 6 +- sql/sql_partition.cc | 467 +++++++++++++-------------- sql/sql_partition.h | 2 +- sql/sql_table.cc | 22 +- sql/sql_yacc.yy | 53 ++- 13 files changed, 500 insertions(+), 450 deletions(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 5c6464b271d..0aaa4e78f68 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,33 @@ drop table if exists t1; +create table t1 (a int) +partition by list (a) +( partition p0 values in (1), +partition p1 values in (1)); +ERROR HY000: Multiple definition of same constant in list partitioning +create table t1 (a int) +partition by list (a) +( partition p0 values in (2, 1), +partition p1 values in (4, NULL, 3)); +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +insert into t1 values (4); +insert into t1 values (NULL); +insert into t1 values (5); +ERROR HY000: Table has no partition for value 5 +drop table t1; +create table t1 (a int) +partition by list column_list(a) +( partition p0 values in (column_list(2), column_list(1)), +partition p1 values in (column_list(4), column_list(NULL), column_list(3))); +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +insert into t1 values (4); +insert into t1 values (NULL); +insert into t1 values (5); +ERROR HY000: Table has no partition for value from column_list +drop table t1; create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index b1f5f4abfcf..f551b58119e 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,38 @@ drop table if exists t1; --enable_warnings +--error ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR +create table t1 (a int) +partition by list (a) +( partition p0 values in (1), + partition p1 values in (1)); + +create table t1 (a int) +partition by list (a) +( partition p0 values in (2, 1), + partition p1 values in (4, NULL, 3)); +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +insert into t1 values (4); +insert into t1 values (NULL); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values (5); +drop table t1; + +create table t1 (a int) +partition by list column_list(a) +( partition p0 values in (column_list(2), column_list(1)), + partition p1 values in (column_list(4), column_list(NULL), column_list(3))); +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +insert into t1 values (4); +insert into t1 values (NULL); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values (5); +drop table t1; + create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ac8c46ec4e3..1b7165dd590 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -244,7 +244,7 @@ void ha_partition::init_handler_variables() /* this allows blackhole to work properly */ - m_no_locks= 0; + m_num_locks= 0; #ifdef DONT_HAVE_TO_BE_INITALIZED m_start_key.flag= 0; @@ -579,8 +579,8 @@ int ha_partition::drop_partitions(const char *path) { List_iterator part_it(m_part_info->partitions); char part_name_buff[FN_REFLEN]; - uint no_parts= m_part_info->partitions.elements; - uint no_subparts= m_part_info->no_subparts; + uint num_parts= m_part_info->partitions.elements; + uint num_subparts= m_part_info->num_subparts; uint i= 0; uint name_variant; int ret_error; @@ -610,7 +610,7 @@ int ha_partition::drop_partitions(const char *path) do { partition_element *sub_elem= sub_it++; - part= i * no_subparts + j; + part= i * num_subparts + j; create_subpartition_name(part_name_buff, path, part_elem->partition_name, sub_elem->partition_name, name_variant); @@ -620,7 +620,7 @@ int ha_partition::drop_partitions(const char *path) error= ret_error; if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -639,7 +639,7 @@ int ha_partition::drop_partitions(const char *path) else part_elem->part_state= PART_IS_DROPPED; } - } while (++i < no_parts); + } while (++i < num_parts); VOID(sync_ddl_log()); DBUG_RETURN(error); } @@ -670,9 +670,9 @@ int ha_partition::rename_partitions(const char *path) List_iterator temp_it(m_part_info->temp_partitions); char part_name_buff[FN_REFLEN]; char norm_name_buff[FN_REFLEN]; - uint no_parts= m_part_info->partitions.elements; + uint num_parts= m_part_info->partitions.elements; uint part_count= 0; - uint no_subparts= m_part_info->no_subparts; + uint num_subparts= m_part_info->num_subparts; uint i= 0; uint j= 0; int error= 0; @@ -720,7 +720,7 @@ int ha_partition::rename_partitions(const char *path) error= 1; else sub_elem->log_entry= NULL; /* Indicate success */ - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -776,7 +776,7 @@ int ha_partition::rename_partitions(const char *path) do { sub_elem= sub_it++; - part= i * no_subparts + j; + part= i * num_subparts + j; create_subpartition_name(norm_name_buff, path, part_elem->partition_name, sub_elem->partition_name, @@ -805,7 +805,7 @@ int ha_partition::rename_partitions(const char *path) error= 1; else sub_elem->log_entry= NULL; - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -837,7 +837,7 @@ int ha_partition::rename_partitions(const char *path) part_elem->log_entry= NULL; } } - } while (++i < no_parts); + } while (++i < num_parts); VOID(sync_ddl_log()); DBUG_RETURN(error); } @@ -1047,8 +1047,8 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, uint flag) { List_iterator part_it(m_part_info->partitions); - uint no_parts= m_part_info->no_parts; - uint no_subparts= m_part_info->no_subparts; + uint num_parts= m_part_info->num_parts; + uint num_subparts= m_part_info->num_subparts; uint i= 0; int error; DBUG_ENTER("ha_partition::handle_opt_partitions"); @@ -1072,7 +1072,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, do { sub_elem= subpart_it++; - part= i * no_subparts + j; + part= i * num_subparts + j; DBUG_PRINT("info", ("Optimize subpartition %u (%s)", part, sub_elem->partition_name)); #ifdef NOT_USED @@ -1096,7 +1096,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, } DBUG_RETURN(error); } - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -1124,7 +1124,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, } } } - } while (++i < no_parts); + } while (++i < num_parts); DBUG_RETURN(FALSE); } @@ -1328,10 +1328,10 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, List_iterator part_it(m_part_info->partitions); List_iterator t_it(m_part_info->temp_partitions); char part_name_buff[FN_REFLEN]; - uint no_parts= m_part_info->partitions.elements; - uint no_subparts= m_part_info->no_subparts; + uint num_parts= m_part_info->partitions.elements; + uint num_subparts= m_part_info->num_subparts; uint i= 0; - uint no_remain_partitions, part_count, orig_count; + uint num_remain_partitions, part_count, orig_count; handler **new_file_array; int error= 1; bool first; @@ -1347,7 +1347,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_name_buff))); m_reorged_parts= 0; if (!m_part_info->is_sub_partitioned()) - no_subparts= 1; + num_subparts= 1; /* Step 1: @@ -1356,7 +1356,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, */ if (temp_partitions) { - m_reorged_parts= temp_partitions * no_subparts; + m_reorged_parts= temp_partitions * num_subparts; } else { @@ -1366,9 +1366,9 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, if (part_elem->part_state == PART_CHANGED || part_elem->part_state == PART_REORGED_DROPPED) { - m_reorged_parts+= no_subparts; + m_reorged_parts+= num_subparts; } - } while (++i < no_parts); + } while (++i < num_parts); } if (m_reorged_parts && !(m_reorged_file= (handler**)sql_calloc(sizeof(handler*)* @@ -1383,10 +1383,10 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, Calculate number of partitions after change and allocate space for their handler references. */ - no_remain_partitions= 0; + num_remain_partitions= 0; if (temp_partitions) { - no_remain_partitions= no_parts * no_subparts; + num_remain_partitions= num_parts * num_subparts; } else { @@ -1399,17 +1399,17 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->part_state == PART_TO_BE_ADDED || part_elem->part_state == PART_CHANGED) { - no_remain_partitions+= no_subparts; + num_remain_partitions+= num_subparts; } - } while (++i < no_parts); + } while (++i < num_parts); } if (!(new_file_array= (handler**)sql_calloc(sizeof(handler*)* - (2*(no_remain_partitions + 1))))) + (2*(num_remain_partitions + 1))))) { - mem_alloc_error(sizeof(handler*)*2*(no_remain_partitions+1)); + mem_alloc_error(sizeof(handler*)*2*(num_remain_partitions+1)); DBUG_RETURN(ER_OUTOFMEMORY); } - m_added_file= &new_file_array[no_remain_partitions + 1]; + m_added_file= &new_file_array[num_remain_partitions + 1]; /* Step 3: @@ -1428,9 +1428,9 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->part_state == PART_REORGED_DROPPED) { memcpy((void*)&m_reorged_file[part_count], - (void*)&m_file[i*no_subparts], - sizeof(handler*)*no_subparts); - part_count+= no_subparts; + (void*)&m_file[i*num_subparts], + sizeof(handler*)*num_subparts); + part_count+= num_subparts; } else if (first && temp_partitions && part_elem->part_state == PART_TO_BE_ADDED) @@ -1445,11 +1445,11 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, ones used to be. */ first= FALSE; - DBUG_ASSERT(((i*no_subparts) + m_reorged_parts) <= m_file_tot_parts); - memcpy((void*)m_reorged_file, &m_file[i*no_subparts], + DBUG_ASSERT(((i*num_subparts) + m_reorged_parts) <= m_file_tot_parts); + memcpy((void*)m_reorged_file, &m_file[i*num_subparts], sizeof(handler*)*m_reorged_parts); } - } while (++i < no_parts); + } while (++i < num_parts); } /* @@ -1467,11 +1467,11 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, partition_element *part_elem= part_it++; if (part_elem->part_state == PART_NORMAL) { - DBUG_ASSERT(orig_count + no_subparts <= m_file_tot_parts); + DBUG_ASSERT(orig_count + num_subparts <= m_file_tot_parts); memcpy((void*)&new_file_array[part_count], (void*)&m_file[orig_count], - sizeof(handler*)*no_subparts); - part_count+= no_subparts; - orig_count+= no_subparts; + sizeof(handler*)*num_subparts); + part_count+= num_subparts; + orig_count+= num_subparts; } else if (part_elem->part_state == PART_CHANGED || part_elem->part_state == PART_TO_BE_ADDED) @@ -1487,16 +1487,16 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, mem_alloc_error(sizeof(handler)); DBUG_RETURN(ER_OUTOFMEMORY); } - } while (++j < no_subparts); + } while (++j < num_subparts); if (part_elem->part_state == PART_CHANGED) - orig_count+= no_subparts; + orig_count+= num_subparts; else if (temp_partitions && first) { - orig_count+= (no_subparts * temp_partitions); + orig_count+= (num_subparts * temp_partitions); first= FALSE; } } - } while (++i < no_parts); + } while (++i < num_parts); first= FALSE; /* Step 5: @@ -1533,7 +1533,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->partition_name, sub_elem->partition_name, name_variant); - part= i * no_subparts + j; + part= i * num_subparts + j; DBUG_PRINT("info", ("Add subpartition %s", part_name_buff)); if ((error= prepare_new_partition(table, create_info, new_file_array[part], @@ -1544,7 +1544,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, DBUG_RETURN(error); } m_added_file[part_count++]= new_file_array[part]; - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -1563,7 +1563,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, m_added_file[part_count++]= new_file_array[i]; } } - } while (++i < no_parts); + } while (++i < num_parts); /* Step 6: @@ -1580,7 +1580,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->part_state= PART_IS_CHANGED; else if (part_elem->part_state == PART_REORGED_DROPPED) part_elem->part_state= PART_TO_BE_DROPPED; - } while (++i < no_parts); + } while (++i < num_parts); for (i= 0; i < temp_partitions; i++) { partition_element *part_elem= t_it++; @@ -1621,9 +1621,9 @@ int ha_partition::copy_partitions(ulonglong * const copied, if (m_part_info->linear_hash_ind) { if (m_part_info->part_type == HASH_PARTITION) - set_linear_hash_mask(m_part_info, m_part_info->no_parts); + set_linear_hash_mask(m_part_info, m_part_info->num_parts); else - set_linear_hash_mask(m_part_info, m_part_info->no_subparts); + set_linear_hash_mask(m_part_info, m_part_info->num_subparts); } while (reorg_part < m_reorged_parts) @@ -1902,7 +1902,7 @@ partition_element *ha_partition::find_partition_element(uint part_id) uint curr_part_id= 0; List_iterator_fast part_it(m_part_info->partitions); - for (i= 0; i < m_part_info->no_parts; i++) + for (i= 0; i < m_part_info->num_parts; i++) { partition_element *part_elem; part_elem= part_it++; @@ -1910,7 +1910,7 @@ partition_element *ha_partition::find_partition_element(uint part_id) { uint j; List_iterator_fast sub_it(part_elem->subpartitions); - for (j= 0; j < m_part_info->no_subparts; j++) + for (j= 0; j < m_part_info->num_subparts; j++) { part_elem= sub_it++; if (part_id == curr_part_id++) @@ -2031,7 +2031,7 @@ bool ha_partition::create_handler_file(const char *name) { partition_element *part_elem, *subpart_elem; uint i, j, part_name_len, subpart_name_len; - uint tot_partition_words, tot_name_len, no_parts; + uint tot_partition_words, tot_name_len, num_parts; uint tot_parts= 0; uint tot_len_words, tot_len_byte, chksum, tot_name_words; char *name_buffer_ptr; @@ -2044,11 +2044,11 @@ bool ha_partition::create_handler_file(const char *name) List_iterator_fast part_it(m_part_info->partitions); DBUG_ENTER("create_handler_file"); - no_parts= m_part_info->partitions.elements; - DBUG_PRINT("info", ("table name = %s, no_parts = %u", name, - no_parts)); + num_parts= m_part_info->partitions.elements; + DBUG_PRINT("info", ("table name = %s, num_parts = %u", name, + num_parts)); tot_name_len= 0; - for (i= 0; i < no_parts; i++) + for (i= 0; i < num_parts; i++) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && @@ -2066,7 +2066,7 @@ bool ha_partition::create_handler_file(const char *name) else { List_iterator_fast sub_it(part_elem->subpartitions); - for (j= 0; j < m_part_info->no_subparts; j++) + for (j= 0; j < m_part_info->num_subparts; j++) { subpart_elem= sub_it++; tablename_to_filename(subpart_elem->partition_name, @@ -2100,7 +2100,7 @@ bool ha_partition::create_handler_file(const char *name) engine_array= (file_buffer + 12); name_buffer_ptr= (char*) (file_buffer + ((4 + tot_partition_words) * 4)); part_it.rewind(); - for (i= 0; i < no_parts; i++) + for (i= 0; i < num_parts; i++) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && @@ -2118,7 +2118,7 @@ bool ha_partition::create_handler_file(const char *name) else { List_iterator_fast sub_it(part_elem->subpartitions); - for (j= 0; j < m_part_info->no_subparts; j++) + for (j= 0; j < m_part_info->num_subparts; j++) { subpart_elem= sub_it++; tablename_to_filename(part_elem->partition_name, part_name, @@ -2254,7 +2254,7 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root) } m_file_tot_parts= m_tot_parts; bzero((char*) m_file, alloc_len); - DBUG_ASSERT(m_part_info->no_parts > 0); + DBUG_ASSERT(m_part_info->num_parts > 0); i= 0; part_count= 0; @@ -2267,7 +2267,7 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root) part_elem= part_it++; if (m_is_sub_partitioned) { - for (j= 0; j < m_part_info->no_subparts; j++) + for (j= 0; j < m_part_info->num_subparts; j++) { if (!(m_file[part_count++]= get_new_handler(table_share, mem_root, part_elem->engine_type))) @@ -2284,7 +2284,7 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root) DBUG_PRINT("info", ("engine_type: %u", (uint) ha_legacy_type(part_elem->engine_type))); } - } while (++i < m_part_info->no_parts); + } while (++i < m_part_info->num_parts); if (part_elem->engine_type == myisam_hton) { DBUG_PRINT("info", ("MyISAM")); @@ -2480,7 +2480,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) if ((error= (*file)->ha_open(table, (const char*) name_buff, mode, test_if_locked))) goto err_handler; - m_no_locks+= (*file)->lock_count(); + m_num_locks+= (*file)->lock_count(); name_buffer_ptr+= strlen(name_buffer_ptr) + 1; set_if_bigger(ref_length, ((*file)->ref_length)); /* @@ -2820,8 +2820,8 @@ int ha_partition::start_stmt(THD *thd, thr_lock_type lock_type) uint ha_partition::lock_count() const { DBUG_ENTER("ha_partition::lock_count"); - DBUG_PRINT("info", ("m_no_locks %d", m_no_locks)); - DBUG_RETURN(m_no_locks); + DBUG_PRINT("info", ("m_num_locks %d", m_num_locks)); + DBUG_RETURN(m_num_locks); } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index cc6558f2db0..3a09c1d2ea3 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -112,7 +112,7 @@ private: uint m_reorged_parts; // Number of reorganised parts uint m_tot_parts; // Total number of partitions; - uint m_no_locks; // For engines like ha_blackhole, which needs no locks + uint m_num_locks; // For engines like ha_blackhole, which needs no locks uint m_last_part; // Last file that we update,write,read int m_lock_type; // Remembers type of last // external_lock @@ -239,10 +239,10 @@ public: size_t pack_frm_len); virtual int drop_partitions(const char *path); virtual int rename_partitions(const char *path); - bool get_no_parts(const char *name, uint *no_parts) + bool get_no_parts(const char *name, uint *num_parts) { DBUG_ENTER("ha_partition::get_no_parts"); - *no_parts= m_tot_parts; + *num_parts= m_tot_parts; DBUG_RETURN(0); } virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index e226b51fc66..801045a8f6d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2638,7 +2638,7 @@ typedef struct st_part_prune_param /* Iterator to be used to obtain the "current" set of used partitions */ PARTITION_ITERATOR part_iter; - /* Initialized bitmap of no_subparts size */ + /* Initialized bitmap of num_subparts size */ MY_BITMAP subparts_bitmap; uchar *cur_min_key; @@ -2904,8 +2904,8 @@ static void mark_full_partition_used_no_parts(partition_info* part_info, static void mark_full_partition_used_with_parts(partition_info *part_info, uint32 part_id) { - uint32 start= part_id * part_info->no_subparts; - uint32 end= start + part_info->no_subparts; + uint32 start= part_id * part_info->num_subparts; + uint32 end= start + part_info->num_subparts; DBUG_ENTER("mark_full_partition_used_with_parts"); for (; start != end; start++) @@ -3328,10 +3328,10 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) != NOT_A_PARTITION_ID) { - for (uint i= 0; i < ppar->part_info->no_subparts; i++) + for (uint i= 0; i < ppar->part_info->num_subparts; i++) if (bitmap_is_set(&ppar->subparts_bitmap, i)) bitmap_set_bit(&ppar->part_info->used_partitions, - part_id * ppar->part_info->no_subparts + i); + part_id * ppar->part_info->num_subparts + i); } goto pop_and_go_right; } @@ -3393,7 +3393,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) NOT_A_PARTITION_ID) { bitmap_set_bit(&part_info->used_partitions, - part_id * part_info->no_subparts + subpart_id); + part_id * part_info->num_subparts + subpart_id); } res= 1; /* Some partitions were marked as used */ goto pop_and_go_right; @@ -3541,10 +3541,10 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) uint used_part_fields, used_subpart_fields; used_part_fields= fields_ok_for_partition_index(part_info->part_field_array) ? - part_info->no_part_fields : 0; + part_info->num_part_fields : 0; used_subpart_fields= fields_ok_for_partition_index(part_info->subpart_field_array)? - part_info->no_subpart_fields : 0; + part_info->num_subpart_fields : 0; uint total_parts= used_part_fields + used_subpart_fields; @@ -3583,10 +3583,10 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) if (ppar->subpart_fields) { my_bitmap_map *buf; - uint32 bufsize= bitmap_buffer_size(ppar->part_info->no_subparts); + uint32 bufsize= bitmap_buffer_size(ppar->part_info->num_subparts); if (!(buf= (my_bitmap_map*) alloc_root(alloc, bufsize))) return TRUE; - bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->no_subparts, + bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->num_subparts, FALSE); } range_par->key_parts= key_part; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index bb7c7c2be0f..aaa6d0d3767 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -75,7 +75,7 @@ partition_info *partition_info::get_clone() SYNOPSIS create_default_partition_names() part_no Partition number for subparts - no_parts Number of partitions + num_parts Number of partitions start_no Starting partition number subpart Is it subpartitions @@ -91,10 +91,10 @@ partition_info *partition_info::get_clone() #define MAX_PART_NAME_SIZE 8 char *partition_info::create_default_partition_names(uint part_no, - uint no_parts_arg, + uint num_parts_arg, uint start_no) { - char *ptr= (char*) sql_calloc(no_parts_arg*MAX_PART_NAME_SIZE); + char *ptr= (char*) sql_calloc(num_parts_arg*MAX_PART_NAME_SIZE); char *move_ptr= ptr; uint i= 0; DBUG_ENTER("create_default_partition_names"); @@ -105,11 +105,11 @@ char *partition_info::create_default_partition_names(uint part_no, { my_sprintf(move_ptr, (move_ptr,"p%u", (start_no + i))); move_ptr+=MAX_PART_NAME_SIZE; - } while (++i < no_parts_arg); + } while (++i < num_parts_arg); } else { - mem_alloc_error(no_parts_arg*MAX_PART_NAME_SIZE); + mem_alloc_error(num_parts_arg*MAX_PART_NAME_SIZE); } DBUG_RETURN(ptr); } @@ -189,19 +189,19 @@ bool partition_info::set_up_default_partitions(handler *file, goto end; } - if ((no_parts == 0) && - ((no_parts= file->get_default_no_partitions(info)) == 0)) + if ((num_parts == 0) && + ((num_parts= file->get_default_no_partitions(info)) == 0)) { my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions"); goto end; } - if (unlikely(no_parts > MAX_PARTITIONS)) + if (unlikely(num_parts > MAX_PARTITIONS)) { my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); goto end; } - if (unlikely((!(default_name= create_default_partition_names(0, no_parts, + if (unlikely((!(default_name= create_default_partition_names(0, num_parts, start_no))))) goto end; i= 0; @@ -220,7 +220,7 @@ bool partition_info::set_up_default_partitions(handler *file, mem_alloc_error(sizeof(partition_element)); goto end; } - } while (++i < no_parts); + } while (++i < num_parts); result= FALSE; end: DBUG_RETURN(result); @@ -259,9 +259,9 @@ bool partition_info::set_up_default_subpartitions(handler *file, List_iterator part_it(partitions); DBUG_ENTER("partition_info::set_up_default_subpartitions"); - if (no_subparts == 0) - no_subparts= file->get_default_no_partitions(info); - if (unlikely((no_parts * no_subparts) > MAX_PARTITIONS)) + if (num_subparts == 0) + num_subparts= file->get_default_no_partitions(info); + if (unlikely((num_parts * num_subparts) > MAX_PARTITIONS)) { my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); goto end; @@ -288,8 +288,8 @@ bool partition_info::set_up_default_subpartitions(handler *file, mem_alloc_error(sizeof(partition_element)); goto end; } - } while (++j < no_subparts); - } while (++i < no_parts); + } while (++j < num_subparts); + } while (++i < num_parts); result= FALSE; end: DBUG_RETURN(result); @@ -520,12 +520,12 @@ bool partition_info::check_engine_mix(handlerton *engine_type, { handlerton *old_engine_type= engine_type; bool first= TRUE; - uint no_parts= partitions.elements; + uint num_parts= partitions.elements; DBUG_ENTER("partition_info::check_engine_mix"); DBUG_PRINT("info", ("in: engine_type = %s, table_engine_set = %u", ha_resolve_storage_engine_name(engine_type), table_engine_set)); - if (no_parts) + if (num_parts) { List_iterator part_it(partitions); uint i= 0; @@ -538,7 +538,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type, if (is_sub_partitioned() && part_elem->subpartitions.elements) { - uint no_subparts= part_elem->subpartitions.elements; + uint num_subparts= part_elem->subpartitions.elements; uint j= 0; List_iterator sub_it(part_elem->subpartitions); do @@ -550,7 +550,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type, if (check_engine_condition(sub_elem, table_engine_set, &engine_type, &first)) goto error; - } while (++j < no_subparts); + } while (++j < num_subparts); /* ensure that the partition also has correct engine */ if (check_engine_condition(part_elem, table_engine_set, &engine_type, &first)) @@ -559,7 +559,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type, else if (check_engine_condition(part_elem, table_engine_set, &engine_type, &first)) goto error; - } while (++i < no_parts); + } while (++i < num_parts); } DBUG_PRINT("info", ("engine_type = %s", ha_resolve_storage_engine_name(engine_type))); @@ -612,21 +612,21 @@ bool partition_info::check_range_constants(THD *thd) List_iterator it(partitions); int result= TRUE; DBUG_ENTER("partition_info::check_range_constants"); - DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", no_parts, + DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", num_parts, column_list)); if (column_list) { part_column_list_val* loc_range_col_array; part_column_list_val *current_largest_col_val; - uint no_column_values= part_field_list.elements; - uint size_entries= sizeof(part_column_list_val) * no_column_values; - range_col_array= (part_column_list_val*)sql_calloc(no_parts * + uint num_column_values= part_field_list.elements; + uint size_entries= sizeof(part_column_list_val) * num_column_values; + range_col_array= (part_column_list_val*)sql_calloc(num_parts * size_entries); LINT_INIT(current_largest_col_val); if (unlikely(range_col_array == NULL)) { - mem_alloc_error(no_parts * sizeof(longlong)); + mem_alloc_error(num_parts * sizeof(longlong)); goto end; } loc_range_col_array= range_col_array; @@ -642,7 +642,7 @@ bool partition_info::check_range_constants(THD *thd) if (fix_column_value_functions(thd, col_val, i)) goto end; memcpy(loc_range_col_array, (const void*)col_val, size_entries); - loc_range_col_array+= no_column_values; + loc_range_col_array+= num_column_values; if (!first) { if (compare_column_values((const void*)current_largest_col_val, @@ -652,7 +652,7 @@ bool partition_info::check_range_constants(THD *thd) current_largest_col_val= col_val; } first= FALSE; - } while (++i < no_parts); + } while (++i < num_parts); } else { @@ -663,17 +663,17 @@ bool partition_info::check_range_constants(THD *thd) LINT_INIT(current_largest); part_result_type= INT_RESULT; - range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong)); + range_int_array= (longlong*)sql_alloc(num_parts * sizeof(longlong)); if (unlikely(range_int_array == NULL)) { - mem_alloc_error(no_parts * sizeof(longlong)); + mem_alloc_error(num_parts * sizeof(longlong)); goto end; } i= 0; do { part_def= it++; - if ((i != (no_parts - 1)) || !defined_max_value) + if ((i != (num_parts - 1)) || !defined_max_value) { part_range_value= part_def->range_value; if (!signed_flag) @@ -687,14 +687,14 @@ bool partition_info::check_range_constants(THD *thd) if (unlikely(current_largest > part_range_value) || (unlikely(current_largest == part_range_value) && (part_range_value < LONGLONG_MAX || - i != (no_parts - 1) || + i != (num_parts - 1) || !defined_max_value))) goto range_not_increasing_error; } range_int_array[i]= part_range_value; current_largest= part_range_value; first= FALSE; - } while (++i < no_parts); + } while (++i < num_parts); } result= FALSE; end: @@ -801,7 +801,7 @@ bool partition_info::fix_column_value_functions(THD *thd, part_column_list_val *col_val, uint part_id) { - uint no_columns= part_field_list.elements; + uint num_columns= part_field_list.elements; Name_resolution_context *context= &thd->lex->current_select->context; TABLE_LIST *save_list= context->table_list; bool result= FALSE; @@ -814,7 +814,7 @@ bool partition_info::fix_column_value_functions(THD *thd, } context->table_list= 0; thd->where= "partition function"; - for (i= 0; i < no_columns; col_val++, i++) + for (i= 0; i < num_columns; col_val++, i++) { Item *column_item= col_val->item_expression; Field *field= part_field_array[i]; @@ -885,7 +885,7 @@ end: bool partition_info::check_list_constants(THD *thd) { - uint i, size_entries, no_column_values; + uint i, size_entries, num_column_values; uint list_index= 0; part_elem_value *list_value; bool result= TRUE; @@ -899,7 +899,7 @@ bool partition_info::check_list_constants(THD *thd) DBUG_ENTER("partition_info::check_list_constants"); part_result_type= INT_RESULT; - no_list_values= 0; + num_list_values= 0; /* We begin by calculating the number of list values that have been defined in the first step. @@ -932,17 +932,17 @@ bool partition_info::check_list_constants(THD *thd) } List_iterator list_val_it1(part_def->list_val_list); while (list_val_it1++) - no_list_values++; - } while (++i < no_parts); + num_list_values++; + } while (++i < num_parts); list_func_it.rewind(); - no_column_values= part_field_list.elements; + num_column_values= part_field_list.elements; size_entries= column_list ? - (no_column_values * sizeof(part_column_list_val)) : + (num_column_values * sizeof(part_column_list_val)) : sizeof(LIST_PART_ENTRY); - ptr= sql_calloc((no_list_values+1) * size_entries); + ptr= sql_calloc((num_list_values+1) * size_entries); if (unlikely(ptr == NULL)) { - mem_alloc_error(no_list_values * size_entries); + mem_alloc_error(num_list_values * size_entries); goto end; } if (column_list) @@ -952,10 +952,6 @@ bool partition_info::check_list_constants(THD *thd) list_col_array= (part_column_list_val*)ptr; compare_func= compare_column_values; i= 0; - /* - Fix to be able to reuse signed sort functions also for unsigned - partition functions. - */ do { part_def= list_func_it++; @@ -968,9 +964,9 @@ bool partition_info::check_list_constants(THD *thd) DBUG_RETURN(TRUE); } memcpy(loc_list_col_array, (const void*)col_val, size_entries); - loc_list_col_array+= no_column_values; + loc_list_col_array+= num_column_values; } - } while (++i < no_parts); + } while (++i < num_parts); } else { @@ -995,24 +991,24 @@ bool partition_info::check_list_constants(THD *thd) list_array[list_index].list_value= calc_value; list_array[list_index++].partition_id= i; } - } while (++i < no_parts); + } while (++i < num_parts); } - if (fixed && no_list_values) + if (fixed && num_list_values) { bool first= TRUE; /* list_array and list_col_array are unions, so this works for both variants of LIST partitioning. */ - my_qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), + my_qsort((void*)list_array, num_list_values, sizeof(LIST_PART_ENTRY), &list_part_cmp); i= 0; LINT_INIT(prev_value); do { - DBUG_ASSERT(i < no_list_values); - curr_value= column_list ? (void*)&list_col_array[no_column_values * i] : + DBUG_ASSERT(i < num_list_values); + curr_value= column_list ? (void*)&list_col_array[num_column_values * i] : (void*)&list_array[i]; if (likely(first || compare_func(curr_value, prev_value))) { @@ -1024,7 +1020,7 @@ bool partition_info::check_list_constants(THD *thd) my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); goto end; } - } while (++i < no_list_values); + } while (++i < num_list_values); } result= FALSE; end: @@ -1088,7 +1084,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } } if (unlikely(!is_sub_partitioned() && - !(use_default_subpartitions && use_default_no_subpartitions))) + !(use_default_subpartitions && use_default_num_subpartitions))) { my_error(ER_SUBPARTITION_ERROR, MYF(0)); goto end; @@ -1154,8 +1150,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, i= 0; { List_iterator part_it(partitions); - uint no_parts_not_set= 0; - uint prev_no_subparts_not_set= no_subparts + 1; + uint num_parts_not_set= 0; + uint prev_num_subparts_not_set= num_subparts + 1; do { partition_element *part_elem= part_it++; @@ -1177,7 +1173,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, { if (part_elem->engine_type == NULL) { - no_parts_not_set++; + num_parts_not_set++; part_elem->engine_type= default_engine_type; } if (check_table_name(part_elem->partition_name, @@ -1192,7 +1188,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, else { uint j= 0; - uint no_subparts_not_set= 0; + uint num_subparts_not_set= 0; List_iterator sub_it(part_elem->subpartitions); partition_element *sub_elem; do @@ -1211,44 +1207,45 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, else { sub_elem->engine_type= default_engine_type; - no_subparts_not_set++; + num_subparts_not_set++; } } DBUG_PRINT("info", ("part = %d sub = %d engine = %s", i, j, ha_resolve_storage_engine_name(sub_elem->engine_type))); - } while (++j < no_subparts); + } while (++j < num_subparts); - if (prev_no_subparts_not_set == (no_subparts + 1) && - (no_subparts_not_set == 0 || no_subparts_not_set == no_subparts)) - prev_no_subparts_not_set= no_subparts_not_set; + if (prev_num_subparts_not_set == (num_subparts + 1) && + (num_subparts_not_set == 0 || + num_subparts_not_set == num_subparts)) + prev_num_subparts_not_set= num_subparts_not_set; if (!table_engine_set && - prev_no_subparts_not_set != no_subparts_not_set) + prev_num_subparts_not_set != num_subparts_not_set) { - DBUG_PRINT("info", ("no_subparts_not_set = %u no_subparts = %u", - no_subparts_not_set, no_subparts)); + DBUG_PRINT("info", ("num_subparts_not_set = %u num_subparts = %u", + num_subparts_not_set, num_subparts)); my_error(ER_MIX_HANDLER_ERROR, MYF(0)); goto end; } if (part_elem->engine_type == NULL) { - if (no_subparts_not_set == 0) + if (num_subparts_not_set == 0) part_elem->engine_type= sub_elem->engine_type; else { - no_parts_not_set++; + num_parts_not_set++; part_elem->engine_type= default_engine_type; } } } - } while (++i < no_parts); + } while (++i < num_parts); if (!table_engine_set && - no_parts_not_set != 0 && - no_parts_not_set != no_parts) + num_parts_not_set != 0 && + num_parts_not_set != num_parts) { - DBUG_PRINT("info", ("no_parts_not_set = %u no_parts = %u", - no_parts_not_set, no_subparts)); + DBUG_PRINT("info", ("num_parts_not_set = %u num_parts = %u", + num_parts_not_set, num_subparts)); my_error(ER_MIX_HANDLER_ERROR, MYF(0)); goto end; } diff --git a/sql/partition_info.h b/sql/partition_info.h index f232e761946..1f2b6b6a95e 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -176,17 +176,17 @@ public: uint part_func_len; uint subpart_func_len; - uint no_parts; - uint no_subparts; + uint num_parts; + uint num_subparts; uint count_curr_subparts; uint part_error_code; - uint no_list_values; + uint num_list_values; - uint no_part_fields; - uint no_subpart_fields; - uint no_full_part_fields; + uint num_part_fields; + uint num_subpart_fields; + uint num_full_part_fields; uint has_null_part_id; /* @@ -197,9 +197,9 @@ public: uint16 linear_hash_mask; bool use_default_partitions; - bool use_default_no_partitions; + bool use_default_num_partitions; bool use_default_subpartitions; - bool use_default_no_subpartitions; + bool use_default_num_subpartitions; bool default_partitions_setup; bool defined_max_value; bool list_of_part_fields; @@ -233,12 +233,12 @@ public: part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION), part_info_len(0), part_state_len(0), part_func_len(0), subpart_func_len(0), - no_parts(0), no_subparts(0), + num_parts(0), num_subparts(0), count_curr_subparts(0), part_error_code(0), - no_list_values(0), no_part_fields(0), no_subpart_fields(0), - no_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0), - use_default_partitions(TRUE), use_default_no_partitions(TRUE), - use_default_subpartitions(TRUE), use_default_no_subpartitions(TRUE), + num_list_values(0), num_part_fields(0), num_subpart_fields(0), + num_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0), + use_default_partitions(TRUE), use_default_num_partitions(TRUE), + use_default_subpartitions(TRUE), use_default_num_subpartitions(TRUE), default_partitions_setup(FALSE), defined_max_value(FALSE), list_of_part_fields(FALSE), list_of_subpart_fields(FALSE), linear_hash_ind(FALSE), fixed(FALSE), @@ -266,7 +266,7 @@ public: /* Returns the total number of partitions on the leaf level */ uint get_tot_partitions() { - return no_parts * (is_sub_partitioned() ? no_subparts : 1); + return num_parts * (is_sub_partitioned() ? num_subparts : 1); } bool set_up_defaults_for_partitioning(handler *file, HA_CREATE_INFO *info, @@ -289,7 +289,7 @@ private: bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info, uint start_no); bool set_up_default_subpartitions(handler *file, HA_CREATE_INFO *info); - char *create_default_partition_names(uint part_no, uint no_parts, + char *create_default_partition_names(uint part_no, uint num_parts, uint start_no); char *create_subpartition_name(uint subpart_no, const char *part_name); bool has_unique_name(partition_element *element); @@ -317,6 +317,6 @@ void init_all_partitions_iterator(partition_info *part_info, PARTITION_ITERATOR *part_iter) { part_iter->part_nums.start= part_iter->part_nums.cur= 0; - part_iter->part_nums.end= part_info->no_parts; + part_iter->part_nums.end= part_info->num_parts; part_iter->get_next= get_next_partition_id_range; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 61f243ece1c..703a97a6565 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1498,7 +1498,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root) keys_onoff(rhs.keys_onoff), tablespace_op(rhs.tablespace_op), partition_names(rhs.partition_names, mem_root), - no_parts(rhs.no_parts), + num_parts(rhs.num_parts), change_level(rhs.change_level), datetime_field(rhs.datetime_field), error_if_not_empty(rhs.error_if_not_empty) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d714e3d0441..3d638689700 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -893,7 +893,7 @@ public: enum enum_enable_or_disable keys_onoff; enum tablespace_op_type tablespace_op; List partition_names; - uint no_parts; + uint num_parts; enum_alter_table_change_level change_level; Create_field *datetime_field; bool error_if_not_empty; @@ -903,7 +903,7 @@ public: flags(0), keys_onoff(LEAVE_AS_IS), tablespace_op(NO_TABLESPACE_OP), - no_parts(0), + num_parts(0), change_level(ALTER_TABLE_METADATA_ONLY), datetime_field(NULL), error_if_not_empty(FALSE) @@ -918,7 +918,7 @@ public: flags= 0; keys_onoff= LEAVE_AS_IS; tablespace_op= NO_TABLESPACE_OP; - no_parts= 0; + num_parts= 0; partition_names.empty(); change_level= ALTER_TABLE_METADATA_ONLY; datetime_field= 0; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 9684e842d40..9a9618108e5 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -202,26 +202,26 @@ bool partition_default_handling(TABLE *table, partition_info *part_info, { DBUG_ENTER("partition_default_handling"); - if (part_info->use_default_no_partitions) + if (part_info->use_default_num_partitions) { if (!is_create_table_ind && - table->file->get_no_parts(normalized_path, &part_info->no_parts)) + table->file->get_no_parts(normalized_path, &part_info->num_parts)) { DBUG_RETURN(TRUE); } } else if (part_info->is_sub_partitioned() && - part_info->use_default_no_subpartitions) + part_info->use_default_num_subpartitions) { - uint no_parts; + uint num_parts; if (!is_create_table_ind && - (table->file->get_no_parts(normalized_path, &no_parts))) + (table->file->get_no_parts(normalized_path, &num_parts))) { DBUG_RETURN(TRUE); } - DBUG_ASSERT(part_info->no_parts > 0); - part_info->no_subparts= no_parts / part_info->no_parts; - DBUG_ASSERT((no_parts % part_info->no_parts) == 0); + DBUG_ASSERT(part_info->num_parts > 0); + part_info->num_subparts= num_parts / part_info->num_parts; + DBUG_ASSERT((num_parts % part_info->num_parts) == 0); } part_info->set_up_defaults_for_partitioning(table->file, (ulonglong)0, (uint)0); @@ -254,8 +254,8 @@ bool check_reorganise_list(partition_info *new_part_info, List list_part_names) { uint new_count, old_count; - uint no_new_parts= new_part_info->partitions.elements; - uint no_old_parts= old_part_info->partitions.elements; + uint num_new_parts= new_part_info->partitions.elements; + uint num_old_parts= old_part_info->partitions.elements; List_iterator new_parts_it(new_part_info->partitions); bool same_part_info= (new_part_info == old_part_info); DBUG_ENTER("check_reorganise_list"); @@ -278,8 +278,8 @@ bool check_reorganise_list(partition_info *new_part_info, if (!is_name_in_list(old_name, list_part_names)) DBUG_RETURN(TRUE); } - } while (old_count < no_old_parts); - } while (new_count < no_new_parts); + } while (old_count < num_old_parts); + } while (new_count < num_new_parts); DBUG_RETURN(FALSE); } @@ -454,7 +454,7 @@ static bool set_up_field_array(TABLE *table, bool is_sub_part) { Field **ptr, *field, **field_array; - uint no_fields= 0; + uint num_fields= 0; uint size_field_array; uint i= 0; uint inx; @@ -466,9 +466,9 @@ static bool set_up_field_array(TABLE *table, while ((field= *(ptr++))) { if (field->flags & GET_FIXED_FIELDS_FLAG) - no_fields++; + num_fields++; } - if (no_fields > MAX_REF_PARTS) + if (num_fields > MAX_REF_PARTS) { char *ptr; if (is_sub_part) @@ -478,7 +478,7 @@ static bool set_up_field_array(TABLE *table, my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), ptr); DBUG_RETURN(TRUE); } - if (no_fields == 0) + if (num_fields == 0) { /* We are using hidden key as partitioning field @@ -486,7 +486,7 @@ static bool set_up_field_array(TABLE *table, DBUG_ASSERT(!is_sub_part); DBUG_RETURN(result); } - size_field_array= (no_fields+1)*sizeof(Field*); + size_field_array= (num_fields+1)*sizeof(Field*); field_array= (Field**)sql_calloc(size_field_array); if (unlikely(!field_array)) { @@ -507,15 +507,15 @@ static bool set_up_field_array(TABLE *table, List_iterator it(part_info->part_field_list); char *field_name; - DBUG_ASSERT(no_fields == part_info->part_field_list.elements); + DBUG_ASSERT(num_fields == part_info->part_field_list.elements); inx= 0; do { field_name= it++; if (!strcmp(field_name, field->field_name)) break; - } while (++inx < no_fields); - if (inx == no_fields) + } while (++inx < num_fields); + if (inx == num_fields) { mem_alloc_error(1); result= TRUE; @@ -543,16 +543,16 @@ static bool set_up_field_array(TABLE *table, } } } - field_array[no_fields]= 0; + field_array[num_fields]= 0; if (!is_sub_part) { part_info->part_field_array= field_array; - part_info->no_part_fields= no_fields; + part_info->num_part_fields= num_fields; } else { part_info->subpart_field_array= field_array; - part_info->no_subpart_fields= no_fields; + part_info->num_subpart_fields= num_fields; } DBUG_RETURN(result); } @@ -591,19 +591,19 @@ static bool create_full_part_field_array(THD *thd, TABLE *table, if (!part_info->is_sub_partitioned()) { part_info->full_part_field_array= part_info->part_field_array; - part_info->no_full_part_fields= part_info->no_part_fields; + part_info->num_full_part_fields= part_info->num_part_fields; } else { Field *field, **field_array; - uint no_part_fields=0, size_field_array; + uint num_part_fields=0, size_field_array; ptr= table->field; while ((field= *(ptr++))) { if (field->flags & FIELD_IN_PART_FUNC_FLAG) - no_part_fields++; + num_part_fields++; } - size_field_array= (no_part_fields+1)*sizeof(Field*); + size_field_array= (num_part_fields+1)*sizeof(Field*); field_array= (Field**)sql_calloc(size_field_array); if (unlikely(!field_array)) { @@ -611,16 +611,16 @@ static bool create_full_part_field_array(THD *thd, TABLE *table, result= TRUE; goto end; } - no_part_fields= 0; + num_part_fields= 0; ptr= table->field; while ((field= *(ptr++))) { if (field->flags & FIELD_IN_PART_FUNC_FLAG) - field_array[no_part_fields++]= field; + field_array[num_part_fields++]= field; } - field_array[no_part_fields]=0; + field_array[num_part_fields]=0; part_info->full_part_field_array= field_array; - part_info->no_full_part_fields= no_part_fields; + part_info->num_full_part_fields= num_part_fields; } /* @@ -821,11 +821,11 @@ static bool handle_list_of_fields(List_iterator it, uint primary_key= table->s->primary_key; if (primary_key != MAX_KEY) { - uint no_key_parts= table->key_info[primary_key].key_parts, i; + uint num_key_parts= table->key_info[primary_key].key_parts, i; /* In the case of an empty list we use primary key as partition key. */ - for (i= 0; i < no_key_parts; i++) + for (i= 0; i < num_key_parts; i++) { Field *field= table->key_info[primary_key].key_part[i].field; field->flags|= GET_FIXED_FIELDS_FLAG; @@ -889,7 +889,7 @@ int check_signed_flag(partition_info *part_info) error= ER_PARTITION_CONST_DOMAIN_ERROR; break; } - } while (++i < part_info->no_parts); + } while (++i < part_info->num_parts); } return error; } @@ -946,13 +946,6 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, bool save_use_only_table_context; DBUG_ENTER("fix_fields_part_func"); - if (part_info->fixed) - { - if (!(is_sub_part || (error= check_signed_flag(part_info)))) - result= FALSE; - goto end; - } - /* Set-up the TABLE_LIST object to be a list with a single table Set the object to zero to create NULL pointers and set alias @@ -1217,9 +1210,9 @@ void check_range_capable_PF(TABLE *table) static bool set_up_partition_bitmap(THD *thd, partition_info *part_info) { uint32 *bitmap_buf; - uint bitmap_bits= part_info->no_subparts? - (part_info->no_subparts* part_info->no_parts): - part_info->no_parts; + uint bitmap_bits= part_info->num_subparts? + (part_info->num_subparts* part_info->num_parts): + part_info->num_parts; uint bitmap_bytes= bitmap_buffer_size(bitmap_bits); DBUG_ENTER("set_up_partition_bitmap"); @@ -1437,22 +1430,22 @@ static void set_up_partition_func_pointers(partition_info *part_info) /* For linear hashing we need a mask which is on the form 2**n - 1 where - 2**n >= no_parts. Thus if no_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7. + 2**n >= num_parts. Thus if num_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7. SYNOPSIS set_linear_hash_mask() part_info Reference to partitioning data structure - no_parts Number of parts in linear hash partitioning + num_parts Number of parts in linear hash partitioning RETURN VALUE NONE */ -void set_linear_hash_mask(partition_info *part_info, uint no_parts) +void set_linear_hash_mask(partition_info *part_info, uint num_parts) { uint mask; - for (mask= 1; mask < no_parts; mask<<=1) + for (mask= 1; mask < num_parts; mask<<=1) ; part_info->linear_hash_mask= mask - 1; } @@ -1466,7 +1459,7 @@ void set_linear_hash_mask(partition_info *part_info, uint no_parts) get_part_id_from_linear_hash() hash_value Hash value calculated by HASH function or KEY function mask Mask calculated previously by set_linear_hash_mask - no_parts Number of partitions in HASH partitioned part + num_parts Number of partitions in HASH partitioned part RETURN VALUE part_id The calculated partition identity (starting at 0) @@ -1479,11 +1472,11 @@ void set_linear_hash_mask(partition_info *part_info, uint no_parts) */ static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask, - uint no_parts) + uint num_parts) { uint32 part_id= (uint32)(hash_value & mask); - if (part_id >= no_parts) + if (part_id >= num_parts) { uint new_mask= ((mask + 1) >> 1) - 1; part_id= (uint32)(hash_value & new_mask); @@ -1627,7 +1620,7 @@ bool fix_partition_func(THD *thd, TABLE *table, function is correct. */ if (part_info->linear_hash_ind) - set_linear_hash_mask(part_info, part_info->no_subparts); + set_linear_hash_mask(part_info, part_info->num_subparts); if (part_info->list_of_subpart_fields) { List_iterator it(part_info->subpart_field_list); @@ -1655,7 +1648,7 @@ bool fix_partition_func(THD *thd, TABLE *table, if (part_info->part_type == HASH_PARTITION) { if (part_info->linear_hash_ind) - set_linear_hash_mask(part_info, part_info->no_parts); + set_linear_hash_mask(part_info, part_info->num_parts); if (part_info->list_of_part_fields) { List_iterator it(part_info->part_field_list); @@ -1708,7 +1701,7 @@ bool fix_partition_func(THD *thd, TABLE *table, my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0)); goto end; } - if (unlikely(part_info->no_parts < 1)) + if (unlikely(part_info->num_parts < 1)) { my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str); goto end; @@ -1852,14 +1845,14 @@ static int add_subpartition_by(File fptr) static int add_part_field_list(File fptr, List field_list) { - uint i, no_fields; + uint i, num_fields; int err= 0; List_iterator part_it(field_list); - no_fields= field_list.elements; + num_fields= field_list.elements; i= 0; err+= add_begin_parenthesis(fptr); - while (i < no_fields) + while (i < num_fields) { const char *field_str= part_it++; String field_string("", 0, system_charset_info); @@ -1870,7 +1863,7 @@ static int add_part_field_list(File fptr, List field_list) strlen(field_str)); thd->options= save_options; err+= add_string_object(fptr, &field_string); - if (i != (no_fields-1)) + if (i != (num_fields-1)) err+= add_comma(fptr); i++; } @@ -1989,10 +1982,10 @@ static int add_column_list_values(File fptr, partition_info *part_info, { int err= 0; uint i; - uint no_elements= part_info->part_field_list.elements; + uint num_elements= part_info->part_field_list.elements; err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); err+= add_begin_parenthesis(fptr); - for (i= 0; i < no_elements; i++) + for (i= 0; i < num_elements; i++) { part_column_list_val *col_val= &list_value->col_val_array[i]; if (col_val->max_value) @@ -2029,7 +2022,7 @@ static int add_column_list_values(File fptr, partition_info *part_info, err+= add_string(fptr,"'"); } } - if (i != (no_elements - 1)) + if (i != (num_elements - 1)) err+= add_string(fptr, comma_str); } err+= add_end_parenthesis(fptr); @@ -2072,13 +2065,13 @@ static int add_partition_values(File fptr, partition_info *part_info, uint i; List_iterator list_val_it(p_elem->list_val_list); err+= add_string(fptr, " VALUES IN "); - uint no_items= p_elem->list_val_list.elements; + uint num_items= p_elem->list_val_list.elements; err+= add_begin_parenthesis(fptr); if (p_elem->has_null_value) { err+= add_string(fptr, "NULL"); - if (no_items == 0) + if (num_items == 0) { err+= add_end_parenthesis(fptr); goto end; @@ -2099,9 +2092,9 @@ static int add_partition_values(File fptr, partition_info *part_info, else err+= add_uint(fptr, list_value->value); } - if (i != (no_items-1)) + if (i != (num_items-1)) err+= add_comma(fptr); - } while (++i < no_items); + } while (++i < num_items); err+= add_end_parenthesis(fptr); } end: @@ -2150,7 +2143,7 @@ char *generate_partition_syntax(partition_info *part_info, bool use_sql_alloc, bool show_partition_options) { - uint i,j, tot_no_parts, no_subparts; + uint i,j, tot_num_parts, num_subparts; partition_element *part_elem; ulonglong buffer_length; char path[FN_REFLEN]; @@ -2207,12 +2200,12 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); err+= add_part_field_list(fptr, part_info->part_field_list); } - if ((!part_info->use_default_no_partitions) && + if ((!part_info->use_default_num_partitions) && part_info->use_default_partitions) { err+= add_string(fptr, "\n"); err+= add_string(fptr, "PARTITIONS "); - err+= add_int(fptr, part_info->no_parts); + err+= add_int(fptr, part_info->num_parts); } if (part_info->is_sub_partitioned()) { @@ -2235,16 +2228,16 @@ char *generate_partition_syntax(partition_info *part_info, part_info->subpart_func_len); err+= add_end_parenthesis(fptr); } - if ((!part_info->use_default_no_subpartitions) && + if ((!part_info->use_default_num_subpartitions) && part_info->use_default_subpartitions) { err+= add_string(fptr, "\n"); err+= add_string(fptr, "SUBPARTITIONS "); - err+= add_int(fptr, part_info->no_subparts); + err+= add_int(fptr, part_info->num_subparts); } } - tot_no_parts= part_info->partitions.elements; - no_subparts= part_info->no_subparts; + tot_num_parts= part_info->partitions.elements; + num_subparts= part_info->num_subparts; if (!part_info->use_default_partitions) { @@ -2288,7 +2281,7 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_name_string(fptr, part_elem->partition_name); if (show_partition_options) err+= add_partition_options(fptr, part_elem); - if (j != (no_subparts-1)) + if (j != (num_subparts-1)) { err+= add_comma(fptr); err+= add_string(fptr, "\n"); @@ -2297,12 +2290,12 @@ char *generate_partition_syntax(partition_info *part_info, } else err+= add_end_parenthesis(fptr); - } while (++j < no_subparts); + } while (++j < num_subparts); } } - if (i == (tot_no_parts-1)) + if (i == (tot_num_parts-1)) err+= add_end_parenthesis(fptr); - } while (++i < tot_no_parts); + } while (++i < tot_num_parts); } if (err) goto close_file; @@ -2449,14 +2442,14 @@ static uint32 calculate_key_value(Field **field_array) get_part_id_for_sub() loc_part_id Local partition id sub_part_id Subpartition id - no_subparts Number of subparts + num_subparts Number of subparts */ inline static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id, - uint no_subparts) + uint num_subparts) { - return (uint32)((loc_part_id * no_subparts) + sub_part_id); + return (uint32)((loc_part_id * num_subparts) + sub_part_id); } @@ -2465,7 +2458,7 @@ static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id, SYNOPSIS get_part_id_hash() - no_parts Number of hash partitions + num_parts Number of hash partitions part_expr Item tree of hash function out:part_id The returned partition id out:func_value Value of hash function @@ -2475,7 +2468,7 @@ static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id, FALSE Success */ -static int get_part_id_hash(uint no_parts, +static int get_part_id_hash(uint num_parts, Item *part_expr, uint32 *part_id, longlong *func_value) @@ -2486,7 +2479,7 @@ static int get_part_id_hash(uint no_parts, if (part_val_int(part_expr, func_value)) DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND); - int_hash_id= *func_value % no_parts; + int_hash_id= *func_value % num_parts; *part_id= int_hash_id < 0 ? (uint32) -int_hash_id : (uint32) int_hash_id; DBUG_RETURN(FALSE); @@ -2500,7 +2493,7 @@ static int get_part_id_hash(uint no_parts, get_part_id_linear_hash() part_info A reference to the partition_info struct where all the desired information is given - no_parts Number of hash partitions + num_parts Number of hash partitions part_expr Item tree of hash function out:part_id The returned partition id out:func_value Value of hash function @@ -2511,7 +2504,7 @@ static int get_part_id_hash(uint no_parts, */ static int get_part_id_linear_hash(partition_info *part_info, - uint no_parts, + uint num_parts, Item *part_expr, uint32 *part_id, longlong *func_value) @@ -2523,7 +2516,7 @@ static int get_part_id_linear_hash(partition_info *part_info, *part_id= get_part_id_from_linear_hash(*func_value, part_info->linear_hash_mask, - no_parts); + num_parts); DBUG_RETURN(FALSE); } @@ -2534,7 +2527,7 @@ static int get_part_id_linear_hash(partition_info *part_info, SYNOPSIS get_part_id_key() field_array Array of fields for PARTTION KEY - no_parts Number of KEY partitions + num_parts Number of KEY partitions RETURN VALUE Calculated partition id @@ -2542,12 +2535,12 @@ static int get_part_id_linear_hash(partition_info *part_info, inline static uint32 get_part_id_key(Field **field_array, - uint no_parts, + uint num_parts, longlong *func_value) { DBUG_ENTER("get_part_id_key"); *func_value= calculate_key_value(field_array); - DBUG_RETURN((uint32) (*func_value % no_parts)); + DBUG_RETURN((uint32) (*func_value % num_parts)); } @@ -2559,7 +2552,7 @@ static uint32 get_part_id_key(Field **field_array, part_info A reference to the partition_info struct where all the desired information is given field_array Array of fields for PARTTION KEY - no_parts Number of KEY partitions + num_parts Number of KEY partitions RETURN VALUE Calculated partition id @@ -2568,7 +2561,7 @@ static uint32 get_part_id_key(Field **field_array, inline static uint32 get_part_id_linear_key(partition_info *part_info, Field **field_array, - uint no_parts, + uint num_parts, longlong *func_value) { DBUG_ENTER("get_part_id_linear_key"); @@ -2576,7 +2569,7 @@ static uint32 get_part_id_linear_key(partition_info *part_info, *func_value= calculate_key_value(field_array); DBUG_RETURN(get_part_id_from_linear_hash(*func_value, part_info->linear_hash_mask, - no_parts)); + num_parts)); } /* @@ -2772,17 +2765,17 @@ int get_partition_id_list_col(partition_info *part_info, longlong *func_value) { part_column_list_val *list_col_array= part_info->list_col_array; - uint no_columns= part_info->part_field_list.elements; + uint num_columns= part_info->part_field_list.elements; int list_index, cmp; int min_list_index= 0; - int max_list_index= part_info->no_list_values - 1; + int max_list_index= part_info->num_list_values - 1; DBUG_ENTER("get_partition_id_list_col"); while (max_list_index >= min_list_index) { list_index= (max_list_index + min_list_index) >> 1; - cmp= cmp_rec_and_tuple(list_col_array + list_index*no_columns, - no_columns); + cmp= cmp_rec_and_tuple(list_col_array + list_index*num_columns, + num_columns); if (cmp > 0) min_list_index= list_index + 1; else if (cmp < 0) @@ -2810,7 +2803,7 @@ int get_partition_id_list(partition_info *part_info, LIST_PART_ENTRY *list_array= part_info->list_array; int list_index; int min_list_index= 0; - int max_list_index= part_info->no_list_values - 1; + int max_list_index= part_info->num_list_values - 1; longlong part_func_value; int error= part_val_int(part_info->part_expr, &part_func_value); longlong list_value; @@ -2880,7 +2873,7 @@ notfound: index idx. The function returns first number idx, such that list_array[idx].list_value is NOT contained within the passed interval. - If all array elements are contained, part_info->no_list_values is + If all array elements are contained, part_info->num_list_values is returned. NOTE @@ -2900,17 +2893,17 @@ uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info, uint32 nparts) { part_column_list_val *list_col_array= part_info->list_col_array; - uint no_columns= part_info->part_field_list.elements; + uint num_columns= part_info->part_field_list.elements; int list_index, cmp; uint min_list_index= 0; - uint max_list_index= part_info->no_list_values - 1; + uint max_list_index= part_info->num_list_values - 1; bool tailf= !(left_endpoint ^ include_endpoint); DBUG_ENTER("get_partition_id_cols_list_for_endpoint"); do { list_index= (max_list_index + min_list_index) >> 1; - cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*no_columns, + cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns, nparts, tailf); if (cmp > 0) min_list_index= list_index + 1; @@ -2953,7 +2946,7 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info, { LIST_PART_ENTRY *list_array= part_info->list_array; uint list_index; - uint min_list_index= 0, max_list_index= part_info->no_list_values - 1; + uint min_list_index= 0, max_list_index= part_info->num_list_values - 1; longlong list_value; /* Get the partitioning function value for the endpoint */ longlong part_func_value= @@ -2967,7 +2960,7 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info, } if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; - DBUG_ASSERT(part_info->no_list_values); + DBUG_ASSERT(part_info->num_list_values); do { list_index= (max_list_index + min_list_index) >> 1; @@ -2997,8 +2990,8 @@ int get_partition_id_range_col(partition_info *part_info, longlong *func_value) { part_column_list_val *range_col_array= part_info->range_col_array; - uint no_columns= part_info->part_field_list.elements; - uint max_partition= part_info->no_parts - 1; + uint num_columns= part_info->part_field_list.elements; + uint max_partition= part_info->num_parts - 1; uint min_part_id= 0; uint max_part_id= max_partition; uint loc_part_id; @@ -3007,21 +3000,21 @@ int get_partition_id_range_col(partition_info *part_info, while (max_part_id > min_part_id) { loc_part_id= (max_part_id + min_part_id + 1) >> 1; - if (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, - no_columns) >= 0) + if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns, + num_columns) >= 0) min_part_id= loc_part_id + 1; else max_part_id= loc_part_id - 1; } loc_part_id= max_part_id; if (loc_part_id != max_partition) - if (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, - no_columns) >= 0) + if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns, + num_columns) >= 0) loc_part_id++; *part_id= (uint32)loc_part_id; if (loc_part_id == max_partition && - (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, - no_columns) >= 0)) + (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns, + num_columns) >= 0)) DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND); DBUG_PRINT("exit",("partition: %d", *part_id)); @@ -3035,7 +3028,7 @@ int get_partition_id_range(partition_info *part_info, longlong *func_value) { longlong *range_array= part_info->range_int_array; - uint max_partition= part_info->no_parts - 1; + uint max_partition= part_info->num_parts - 1; uint min_part_id= 0; uint max_part_id= max_partition; uint loc_part_id; @@ -3112,7 +3105,7 @@ int get_partition_id_range(partition_info *part_info, represented by range_int_array[idx] has EMPTY intersection with the passed interval. If the interval represented by the last array element has non-empty - intersection with the passed interval, part_info->no_parts is + intersection with the passed interval, part_info->num_parts is returned. RETURN @@ -3140,7 +3133,7 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, bool include_endpoint) { longlong *range_array= part_info->range_int_array; - uint max_partition= part_info->no_parts - 1; + uint max_partition= part_info->num_parts - 1; uint min_part_id= 0, max_part_id= max_partition, loc_part_id; /* Get the partitioning function value for the endpoint */ longlong part_func_value= @@ -3205,7 +3198,7 @@ int get_partition_id_hash_nosub(partition_info *part_info, uint32 *part_id, longlong *func_value) { - return get_part_id_hash(part_info->no_parts, part_info->part_expr, + return get_part_id_hash(part_info->num_parts, part_info->part_expr, part_id, func_value); } @@ -3214,7 +3207,7 @@ int get_partition_id_linear_hash_nosub(partition_info *part_info, uint32 *part_id, longlong *func_value) { - return get_part_id_linear_hash(part_info, part_info->no_parts, + return get_part_id_linear_hash(part_info, part_info->num_parts, part_info->part_expr, part_id, func_value); } @@ -3224,7 +3217,7 @@ int get_partition_id_key_nosub(partition_info *part_info, longlong *func_value) { *part_id= get_part_id_key(part_info->part_field_array, - part_info->no_parts, func_value); + part_info->num_parts, func_value); return 0; } @@ -3235,7 +3228,7 @@ int get_partition_id_linear_key_nosub(partition_info *part_info, { *part_id= get_part_id_linear_key(part_info, part_info->part_field_array, - part_info->no_parts, func_value); + part_info->num_parts, func_value); return 0; } @@ -3245,7 +3238,7 @@ int get_partition_id_with_sub(partition_info *part_info, longlong *func_value) { uint32 loc_part_id, sub_part_id; - uint no_subparts; + uint num_subparts; int error; DBUG_ENTER("get_partition_id_with_sub"); @@ -3255,13 +3248,13 @@ int get_partition_id_with_sub(partition_info *part_info, { DBUG_RETURN(error); } - no_subparts= part_info->no_subparts; + num_subparts= part_info->num_subparts; if (unlikely((error= part_info->get_subpartition_id(part_info, &sub_part_id)))) { DBUG_RETURN(error); } - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); + *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, num_subparts); DBUG_RETURN(0); } @@ -3294,7 +3287,7 @@ int get_partition_id_hash_sub(partition_info *part_info, uint32 *part_id) { longlong func_value; - return get_part_id_hash(part_info->no_subparts, part_info->subpart_expr, + return get_part_id_hash(part_info->num_subparts, part_info->subpart_expr, part_id, &func_value); } @@ -3303,7 +3296,7 @@ int get_partition_id_linear_hash_sub(partition_info *part_info, uint32 *part_id) { longlong func_value; - return get_part_id_linear_hash(part_info, part_info->no_subparts, + return get_part_id_linear_hash(part_info, part_info->num_subparts, part_info->subpart_expr, part_id, &func_value); } @@ -3314,7 +3307,7 @@ int get_partition_id_key_sub(partition_info *part_info, { longlong func_value; *part_id= get_part_id_key(part_info->subpart_field_array, - part_info->no_subparts, &func_value); + part_info->num_subparts, &func_value); return FALSE; } @@ -3325,7 +3318,7 @@ int get_partition_id_linear_key_sub(partition_info *part_info, longlong func_value; *part_id= get_part_id_linear_key(part_info, part_info->subpart_field_array, - part_info->no_subparts, &func_value); + part_info->num_subparts, &func_value); return FALSE; } @@ -3624,16 +3617,16 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, const key_range *key_spec, part_id_range *part_spec) { partition_info *part_info= table->part_info; - uint no_parts= part_info->get_tot_partitions(); + uint num_parts= part_info->get_tot_partitions(); uint i, part_id; - uint sub_part= no_parts; - uint32 part_part= no_parts; + uint sub_part= num_parts; + uint32 part_part= num_parts; KEY *key_info= NULL; bool found_part_field= FALSE; DBUG_ENTER("get_partition_set"); part_spec->start_part= 0; - part_spec->end_part= no_parts - 1; + part_spec->end_part= num_parts - 1; if ((index < MAX_KEY) && key_spec->flag == (uint)HA_READ_KEY_EXACT && part_info->some_fields_in_PF.is_set(index)) @@ -3670,7 +3663,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, { if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part)) { - part_spec->start_part= no_parts; + part_spec->start_part= num_parts; DBUG_VOID_RETURN; } } @@ -3684,7 +3677,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, allowed values. Thus it is certain that the result of this scan will be empty. */ - part_spec->start_part= no_parts; + part_spec->start_part= num_parts; DBUG_VOID_RETURN; } } @@ -3722,7 +3715,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, { if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part)) { - part_spec->start_part= no_parts; + part_spec->start_part= num_parts; clear_indicator_in_key_fields(key_info); DBUG_VOID_RETURN; } @@ -3731,7 +3724,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, { if (get_part_id_from_key(table,buf,key_info,key_spec,&part_part)) { - part_spec->start_part= no_parts; + part_spec->start_part= num_parts; clear_indicator_in_key_fields(key_info); DBUG_VOID_RETURN; } @@ -3752,29 +3745,29 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, nothing or we have discovered a range of partitions with possible holes in it. We need a bitvector to further the work here. */ - if (!(part_part == no_parts && sub_part == no_parts)) + if (!(part_part == num_parts && sub_part == num_parts)) { /* We can only arrive here if we are using subpartitioning. */ - if (part_part != no_parts) + if (part_part != num_parts) { /* We know the top partition and need to scan all underlying subpartitions. This is a range without holes. */ - DBUG_ASSERT(sub_part == no_parts); - part_spec->start_part= part_part * part_info->no_subparts; - part_spec->end_part= part_spec->start_part+part_info->no_subparts - 1; + DBUG_ASSERT(sub_part == num_parts); + part_spec->start_part= part_part * part_info->num_subparts; + part_spec->end_part= part_spec->start_part+part_info->num_subparts - 1; } else { - DBUG_ASSERT(sub_part != no_parts); + DBUG_ASSERT(sub_part != num_parts); part_spec->start_part= sub_part; part_spec->end_part=sub_part+ - (part_info->no_subparts*(part_info->no_parts-1)); - for (i= 0, part_id= sub_part; i < part_info->no_parts; - i++, part_id+= part_info->no_subparts) + (part_info->num_subparts*(part_info->num_parts-1)); + for (i= 0, part_id= sub_part; i < part_info->num_parts; + i++, part_id+= part_info->num_subparts) ; //Set bit part_id in bit array } } @@ -4038,9 +4031,9 @@ set_engine_all_partitions(partition_info *part_info, partition_element *sub_elem= sub_it++; sub_elem->engine_type= engine_type; - } while (++j < part_info->no_subparts); + } while (++j < part_info->num_subparts); } - } while (++i < part_info->no_parts); + } while (++i < part_info->num_parts); } /* SYNOPSIS @@ -4185,7 +4178,7 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info, enum partition_state part_state) { uint part_count= 0; - uint no_parts_found= 0; + uint num_parts_found= 0; List_iterator part_it(tab_part_info->partitions); do @@ -4200,13 +4193,13 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info, I.e mark the partition as a partition to be "changed" by analyzing/optimizing/rebuilding/checking/repairing */ - no_parts_found++; + num_parts_found++; part_elem->part_state= part_state; DBUG_PRINT("info", ("Setting part_state to %u for partition %s", part_state, part_elem->partition_name)); } - } while (++part_count < tab_part_info->no_parts); - return no_parts_found; + } while (++part_count < tab_part_info->num_parts); + return num_parts_found; } @@ -4287,13 +4280,13 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, { uint new_part_no, curr_part_no; if (tab_part_info->part_type != HASH_PARTITION || - tab_part_info->use_default_no_partitions) + tab_part_info->use_default_num_partitions) { my_error(ER_REORG_NO_PARAM_ERROR, MYF(0)); DBUG_RETURN(TRUE); } new_part_no= table->file->get_default_no_partitions(create_info); - curr_part_no= tab_part_info->no_parts; + curr_part_no= tab_part_info->num_parts; if (new_part_no == curr_part_no) { /* @@ -4311,7 +4304,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, setting the flag for no default number of partitions */ alter_info->flags|= ALTER_ADD_PARTITION; - thd->work_part_info->no_parts= new_part_no - curr_part_no; + thd->work_part_info->num_parts= new_part_no - curr_part_no; } else { @@ -4320,7 +4313,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, without setting the flag for no default number of partitions */ alter_info->flags|= ALTER_COALESCE_PARTITION; - alter_info->no_parts= curr_part_no - new_part_no; + alter_info->num_parts= curr_part_no - new_part_no; } } if (!(flags= table->file->alter_table_flags(alter_info->flags))) @@ -4378,9 +4371,9 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, partitioning scheme as currently set-up. Partitions are always added at the end in ADD PARTITION. */ - uint no_new_partitions= alt_part_info->no_parts; - uint no_orig_partitions= tab_part_info->no_parts; - uint check_total_partitions= no_new_partitions + no_orig_partitions; + uint num_new_partitions= alt_part_info->num_parts; + uint num_orig_partitions= tab_part_info->num_parts; + uint check_total_partitions= num_new_partitions + num_orig_partitions; uint new_total_partitions= check_total_partitions; /* We allow quite a lot of values to be supplied by defaults, however we @@ -4397,22 +4390,22 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0)); DBUG_RETURN(TRUE); } - if (no_new_partitions == 0) + if (num_new_partitions == 0) { my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0)); DBUG_RETURN(TRUE); } if (tab_part_info->is_sub_partitioned()) { - if (alt_part_info->no_subparts == 0) - alt_part_info->no_subparts= tab_part_info->no_subparts; - else if (alt_part_info->no_subparts != tab_part_info->no_subparts) + if (alt_part_info->num_subparts == 0) + alt_part_info->num_subparts= tab_part_info->num_subparts; + else if (alt_part_info->num_subparts != tab_part_info->num_subparts) { my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0)); DBUG_RETURN(TRUE); } check_total_partitions= new_total_partitions* - alt_part_info->no_subparts; + alt_part_info->num_subparts; } if (check_total_partitions > MAX_PARTITIONS) { @@ -4422,8 +4415,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, alt_part_info->part_type= tab_part_info->part_type; alt_part_info->subpart_type= tab_part_info->subpart_type; if (alt_part_info->set_up_defaults_for_partitioning(table->file, - ULL(0), - tab_part_info->no_parts)) + ULL(0), + tab_part_info->num_parts)) { DBUG_RETURN(TRUE); } @@ -4498,7 +4491,7 @@ that are reorganised. uint lower_2n= upper_2n >> 1; bool all_parts= TRUE; if (tab_part_info->linear_hash_ind && - no_new_partitions < upper_2n) + num_new_partitions < upper_2n) { /* An analysis of which parts needs reorganisation shows that it is @@ -4507,7 +4500,7 @@ that are reorganised. onwards it starts again from partition 0 and goes on until it reaches p(upper_2n - 1). If the last new partition reaches beyond upper_2n - 1 then the first interval will end with - p(lower_2n - 1) and start with p(no_orig_partitions - lower_2n). + p(lower_2n - 1) and start with p(num_orig_partitions - lower_2n). If lower_2n partitions are added then p0 to p(lower_2n - 1) will be reorganised which means that the two interval becomes one interval at this point. Thus only when adding less than @@ -4535,7 +4528,7 @@ that are reorganised. to TRUE. In this case we don't get into this if-part at all. */ all_parts= FALSE; - if (no_new_partitions >= lower_2n) + if (num_new_partitions >= lower_2n) { /* In this case there is only one interval since the two intervals @@ -4551,8 +4544,8 @@ that are reorganised. Also in this case there is only one interval since we are not going over a 2**n boundary */ - start_part= no_orig_partitions - lower_2n; - end_part= start_part + (no_new_partitions - 1); + start_part= num_orig_partitions - lower_2n; + end_part= start_part + (num_new_partitions - 1); } else { @@ -4561,7 +4554,7 @@ that are reorganised. new parts that would ensure that the intervals become overlapping. */ - start_part= no_orig_partitions - lower_2n; + start_part= num_orig_partitions - lower_2n; end_part= upper_2n - 1; start_sec_part= 0; end_sec_part= new_total_partitions - (upper_2n + 1); @@ -4578,7 +4571,7 @@ that are reorganised. { p_elem->part_state= PART_CHANGED; } - } while (++part_no < no_orig_partitions); + } while (++part_no < num_orig_partitions); } /* Need to concatenate the lists here to make it possible to check the @@ -4601,8 +4594,8 @@ that are reorganised. mem_alloc_error(1); DBUG_RETURN(TRUE); } - } while (++part_count < no_new_partitions); - tab_part_info->no_parts+= no_new_partitions; + } while (++part_count < num_new_partitions); + tab_part_info->num_parts+= num_new_partitions; } /* If we specify partitions explicitly we don't use defaults anymore. @@ -4617,7 +4610,7 @@ that are reorganised. DBUG_PRINT("info", ("part_info: 0x%lx", (long) tab_part_info)); tab_part_info->use_default_partitions= FALSE; } - tab_part_info->use_default_no_partitions= FALSE; + tab_part_info->use_default_num_partitions= FALSE; tab_part_info->is_auto_partitioned= FALSE; } } @@ -4631,8 +4624,8 @@ that are reorganised. command to drop the partition failed in the middle. */ uint part_count= 0; - uint no_parts_dropped= alter_info->partition_names.elements; - uint no_parts_found= 0; + uint num_parts_dropped= alter_info->partition_names.elements; + uint num_parts_found= 0; List_iterator part_it(tab_part_info->partitions); tab_part_info->is_auto_partitioned= FALSE; @@ -4642,7 +4635,7 @@ that are reorganised. my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP"); DBUG_RETURN(TRUE); } - if (no_parts_dropped >= tab_part_info->no_parts) + if (num_parts_dropped >= tab_part_info->num_parts) { my_error(ER_DROP_LAST_PARTITION, MYF(0)); DBUG_RETURN(TRUE); @@ -4656,11 +4649,11 @@ that are reorganised. /* Set state to indicate that the partition is to be dropped. */ - no_parts_found++; + num_parts_found++; part_elem->part_state= PART_TO_BE_DROPPED; } - } while (++part_count < tab_part_info->no_parts); - if (no_parts_found != no_parts_dropped) + } while (++part_count < tab_part_info->num_parts); + if (num_parts_found != num_parts_dropped) { my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP"); DBUG_RETURN(TRUE); @@ -4670,14 +4663,14 @@ that are reorganised. my_error(ER_ROW_IS_REFERENCED, MYF(0)); DBUG_RETURN(TRUE); } - tab_part_info->no_parts-= no_parts_dropped; + tab_part_info->num_parts-= num_parts_dropped; } else if (alter_info->flags & ALTER_REBUILD_PARTITION) { - uint no_parts_found; - uint no_parts_opt= alter_info->partition_names.elements; - no_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED); - if (no_parts_found != no_parts_opt && + uint num_parts_found; + uint num_parts_opt= alter_info->partition_names.elements; + num_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED); + if (num_parts_found != num_parts_opt && (!(alter_info->flags & ALTER_ALL_PARTITION))) { my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD"); @@ -4691,20 +4684,20 @@ that are reorganised. } else if (alter_info->flags & ALTER_COALESCE_PARTITION) { - uint no_parts_coalesced= alter_info->no_parts; - uint no_parts_remain= tab_part_info->no_parts - no_parts_coalesced; + uint num_parts_coalesced= alter_info->num_parts; + uint num_parts_remain= tab_part_info->num_parts - num_parts_coalesced; List_iterator part_it(tab_part_info->partitions); if (tab_part_info->part_type != HASH_PARTITION) { my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0)); DBUG_RETURN(TRUE); } - if (no_parts_coalesced == 0) + if (num_parts_coalesced == 0) { my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0)); DBUG_RETURN(TRUE); } - if (no_parts_coalesced >= tab_part_info->no_parts) + if (num_parts_coalesced >= tab_part_info->num_parts) { my_error(ER_DROP_LAST_PARTITION, MYF(0)); DBUG_RETURN(TRUE); @@ -4752,21 +4745,21 @@ state of p1. uint upper_2n= tab_part_info->linear_hash_mask + 1; uint lower_2n= upper_2n >> 1; all_parts= FALSE; - if (no_parts_coalesced >= lower_2n) + if (num_parts_coalesced >= lower_2n) { all_parts= TRUE; } - else if (no_parts_remain >= lower_2n) + else if (num_parts_remain >= lower_2n) { - end_part= tab_part_info->no_parts - (lower_2n + 1); - start_part= no_parts_remain - lower_2n; + end_part= tab_part_info->num_parts - (lower_2n + 1); + start_part= num_parts_remain - lower_2n; } else { start_part= 0; - end_part= tab_part_info->no_parts - (lower_2n + 1); + end_part= tab_part_info->num_parts - (lower_2n + 1); end_sec_part= (lower_2n >> 1) - 1; - start_sec_part= end_sec_part - (lower_2n - (no_parts_remain + 1)); + start_sec_part= end_sec_part - (lower_2n - (num_parts_remain + 1)); } } do @@ -4777,19 +4770,19 @@ state of p1. (part_count >= start_part && part_count <= end_part) || (part_count >= start_sec_part && part_count <= end_sec_part))) p_elem->part_state= PART_CHANGED; - if (++part_count > no_parts_remain) + if (++part_count > num_parts_remain) { if (*fast_alter_partition) p_elem->part_state= PART_REORGED_DROPPED; else part_it.remove(); } - } while (part_count < tab_part_info->no_parts); - tab_part_info->no_parts= no_parts_remain; + } while (part_count < tab_part_info->num_parts); + tab_part_info->num_parts= num_parts_remain; } if (!(alter_info->flags & ALTER_TABLE_REORG)) { - tab_part_info->use_default_no_partitions= FALSE; + tab_part_info->use_default_num_partitions= FALSE; tab_part_info->is_auto_partitioned= FALSE; } } @@ -4806,32 +4799,32 @@ state of p1. range as those changed from. This command can be used on RANGE and LIST partitions. */ - uint no_parts_reorged= alter_info->partition_names.elements; - uint no_parts_new= thd->work_part_info->partitions.elements; + uint num_parts_reorged= alter_info->partition_names.elements; + uint num_parts_new= thd->work_part_info->partitions.elements; uint check_total_partitions; tab_part_info->is_auto_partitioned= FALSE; - if (no_parts_reorged > tab_part_info->no_parts) + if (num_parts_reorged > tab_part_info->num_parts) { my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0)); DBUG_RETURN(TRUE); } if (!(tab_part_info->part_type == RANGE_PARTITION || tab_part_info->part_type == LIST_PARTITION) && - (no_parts_new != no_parts_reorged)) + (num_parts_new != num_parts_reorged)) { my_error(ER_REORG_HASH_ONLY_ON_SAME_NO, MYF(0)); DBUG_RETURN(TRUE); } if (tab_part_info->is_sub_partitioned() && - alt_part_info->no_subparts && - alt_part_info->no_subparts != tab_part_info->no_subparts) + alt_part_info->num_subparts && + alt_part_info->num_subparts != tab_part_info->num_subparts) { my_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR, MYF(0)); DBUG_RETURN(TRUE); } - check_total_partitions= tab_part_info->no_parts + no_parts_new; - check_total_partitions-= no_parts_reorged; + check_total_partitions= tab_part_info->num_parts + num_parts_new; + check_total_partitions-= num_parts_reorged; if (check_total_partitions > MAX_PARTITIONS) { my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); @@ -4839,7 +4832,7 @@ state of p1. } alt_part_info->part_type= tab_part_info->part_type; alt_part_info->subpart_type= tab_part_info->subpart_type; - alt_part_info->no_subparts= tab_part_info->no_subparts; + alt_part_info->num_subparts= tab_part_info->num_subparts; DBUG_ASSERT(!alt_part_info->use_default_partitions); if (alt_part_info->set_up_defaults_for_partitioning(table->file, ULL(0), @@ -4936,7 +4929,7 @@ the generated partition syntax in a correct manner. tab_it.replace(alt_part_elem); else tab_it.after(alt_part_elem); - } while (++alt_part_count < no_parts_new); + } while (++alt_part_count < num_parts_new); } else if (found_last) { @@ -4951,13 +4944,13 @@ the generated partition syntax in a correct manner. if (found_first) found_last= TRUE; } - } while (++part_count < tab_part_info->no_parts); - if (drop_count != no_parts_reorged) + } while (++part_count < tab_part_info->num_parts); + if (drop_count != num_parts_reorged) { my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE"); DBUG_RETURN(TRUE); } - tab_part_info->no_parts= check_total_partitions; + tab_part_info->num_parts= check_total_partitions; } } else @@ -4973,7 +4966,7 @@ the generated partition syntax in a correct manner. !alt_part_info->use_default_subpartitions) { tab_part_info->use_default_subpartitions= FALSE; - tab_part_info->use_default_no_subpartitions= FALSE; + tab_part_info->use_default_num_subpartitions= FALSE; } if (tab_part_info->check_partition_info(thd, (handlerton**)NULL, table->file, ULL(0), TRUE)) @@ -5285,8 +5278,8 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) part_it.remove(); remove_count++; } - } while (++i < part_info->no_parts); - part_info->no_parts-= remove_count; + } while (++i < part_info->num_parts); + part_info->num_parts-= remove_count; DBUG_RETURN(FALSE); } @@ -5408,7 +5401,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, char normal_path[FN_REFLEN]; List_iterator part_it(part_info->partitions); uint temp_partitions= part_info->temp_partitions.elements; - uint no_elements= part_info->partitions.elements; + uint num_elements= part_info->partitions.elements; uint i= 0; DBUG_ENTER("write_log_changed_partitions"); @@ -5421,7 +5414,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, if (part_info->is_sub_partitioned()) { List_iterator sub_it(part_elem->subpartitions); - uint no_subparts= part_info->no_subparts; + uint num_subparts= part_info->num_subparts; uint j= 0; do { @@ -5450,7 +5443,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, *next_entry= log_entry->entry_pos; sub_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -5478,7 +5471,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, insert_part_info_log_entry_list(part_info, log_entry); } } - } while (++i < no_elements); + } while (++i < num_elements); DBUG_RETURN(FALSE); } @@ -5504,14 +5497,14 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, char tmp_path[FN_LEN]; List_iterator part_it(part_info->partitions); List_iterator temp_it(part_info->temp_partitions); - uint no_temp_partitions= part_info->temp_partitions.elements; - uint no_elements= part_info->partitions.elements; + uint num_temp_partitions= part_info->temp_partitions.elements; + uint num_elements= part_info->partitions.elements; DBUG_ENTER("write_log_dropped_partitions"); ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; if (temp_list) - no_elements= no_temp_partitions; - while (no_elements--) + num_elements= num_temp_partitions; + while (num_elements--) { partition_element *part_elem; if (temp_list) @@ -5525,14 +5518,14 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint name_variant; if (part_elem->part_state == PART_CHANGED || (part_elem->part_state == PART_TO_BE_ADDED && - no_temp_partitions)) + num_temp_partitions)) name_variant= TEMP_PART_NAME; else name_variant= NORMAL_PART_NAME; if (part_info->is_sub_partitioned()) { List_iterator sub_it(part_elem->subpartitions); - uint no_subparts= part_info->no_subparts; + uint num_subparts= part_info->num_subparts; uint j= 0; do { @@ -5552,7 +5545,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, *next_entry= log_entry->entry_pos; sub_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -6705,7 +6698,7 @@ static void set_up_range_analysis_info(partition_info *part_info) Check if get_part_iter_for_interval_via_walking() can be used for partitioning */ - if (part_info->no_part_fields == 1) + if (part_info->num_part_fields == 1) { Field *field= part_info->part_field_array[0]; switch (field->type()) { @@ -6727,7 +6720,7 @@ setup_subparts: Check if get_part_iter_for_interval_via_walking() can be used for subpartitioning */ - if (part_info->no_subpart_fields == 1) + if (part_info->num_subpart_fields == 1) { Field *field= part_info->subpart_field_array[0]; switch (field->type()) { @@ -6841,7 +6834,7 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint, typedef uint32 (*get_col_endpoint_func)(partition_info*, bool left_endpoint, bool include_endpoint, - uint32 no_parts); + uint32 num_parts); /* Partitioning Interval Analysis: Initialize the iterator for "mapping" case @@ -6883,10 +6876,10 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, bool include_endpoint, uint32 nparts) { - uint max_partition= part_info->no_parts - 1; + uint max_partition= part_info->num_parts - 1; uint min_part_id= 0, max_part_id= max_partition, loc_part_id; part_column_list_val *range_col_array= part_info->range_col_array; - uint no_columns= part_info->part_field_list.elements; + uint num_columns= part_info->part_field_list.elements; bool tailf= !(left_endpoint ^ include_endpoint); DBUG_ENTER("get_partition_id_cols_range_for_endpoint"); @@ -6894,7 +6887,7 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, while (max_part_id > min_part_id) { loc_part_id= (max_part_id + min_part_id + 1) >> 1; - if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*no_columns, + if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns, nparts, tailf) >= 0) min_part_id= loc_part_id + 1; else @@ -6902,7 +6895,7 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, } loc_part_id= max_part_id; if (loc_part_id < max_partition && - cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*no_columns, + cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*num_columns, nparts, tailf) >= 0 ) { @@ -6910,7 +6903,7 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, } if (left_endpoint) { - if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*no_columns, + if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns, nparts, tailf) >= 0) loc_part_id++; } @@ -6919,7 +6912,7 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, if (loc_part_id < max_partition) { int res= cmp_rec_and_tuple_prune(range_col_array + - loc_part_id * no_columns, + loc_part_id * num_columns, nparts, tailf); if (!res) loc_part_id += test(include_endpoint); @@ -6969,7 +6962,7 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, nparts); } if (flags & NO_MAX_RANGE) - part_iter->part_nums.end= part_info->no_parts; + part_iter->part_nums.end= part_info->num_parts; else { // Copy from max_value to record @@ -7012,7 +7005,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, get_endpoint= get_partition_id_range_for_endpoint_charset; else get_endpoint= get_partition_id_range_for_endpoint; - max_endpoint_val= part_info->no_parts; + max_endpoint_val= part_info->num_parts; part_iter->get_next= get_next_partition_id_range; } else if (part_info->part_type == LIST_PARTITION) @@ -7022,7 +7015,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, get_endpoint= get_list_array_idx_for_endpoint_charset; else get_endpoint= get_list_array_idx_for_endpoint; - max_endpoint_val= part_info->no_list_values; + max_endpoint_val= part_info->num_list_values; part_iter->get_next= get_next_partition_id_list; part_iter->part_info= part_info; if (max_endpoint_val == 0) @@ -7166,13 +7159,13 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, if (is_subpart) { field= part_info->subpart_field_array[0]; - total_parts= part_info->no_subparts; + total_parts= part_info->num_subparts; get_next_func= get_next_subpartition_via_walking; } else { field= part_info->part_field_array[0]; - total_parts= part_info->no_parts; + total_parts= part_info->num_parts; get_next_func= get_next_partition_via_walking; } diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 7902cc77877..8fce2ebe6d1 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -65,7 +65,7 @@ int get_part_for_delete(const uchar *buf, const uchar *rec0, void prune_partition_set(const TABLE *table, part_id_range *part_spec); bool check_partition_info(partition_info *part_info,handlerton **eng_type, TABLE *table, handler *file, HA_CREATE_INFO *info); -void set_linear_hash_mask(partition_info *part_info, uint no_parts); +void set_linear_hash_mask(partition_info *part_info, uint num_parts); bool fix_partition_func(THD *thd, TABLE *table, bool create_table_ind); char *generate_partition_syntax(partition_info *part_info, uint *buf_length, bool use_sql_alloc, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index fce51c7e3da..efc75db8e02 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3700,9 +3700,9 @@ bool mysql_create_table_no_lock(THD *thd, creates a proper .par file. The current part_info object is only used to create the frm-file and .par-file. */ - if (part_info->use_default_no_partitions && - part_info->no_parts && - (int)part_info->no_parts != + if (part_info->use_default_num_partitions && + part_info->num_parts && + (int)part_info->num_parts != file->get_default_no_partitions(create_info)) { uint i; @@ -3713,13 +3713,13 @@ bool mysql_create_table_no_lock(THD *thd, (part_it++)->part_state= PART_TO_BE_DROPPED; } else if (part_info->is_sub_partitioned() && - part_info->use_default_no_subpartitions && - part_info->no_subparts && - (int)part_info->no_subparts != + part_info->use_default_num_subpartitions && + part_info->num_subparts && + (int)part_info->num_subparts != file->get_default_no_partitions(create_info)) { DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE); - part_info->no_subparts= file->get_default_no_partitions(create_info); + part_info->num_subparts= file->get_default_no_partitions(create_info); } } else if (create_info->db_type != engine_type) @@ -4531,11 +4531,11 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); DBUG_RETURN(TRUE); } - uint no_parts_found; - uint no_parts_opt= alter_info->partition_names.elements; - no_parts_found= set_part_state(alter_info, table->table->part_info, + uint num_parts_found; + uint num_parts_opt= alter_info->partition_names.elements; + num_parts_found= set_part_state(alter_info, table->table->part_info, PART_CHANGED); - if (no_parts_found != no_parts_opt && + if (num_parts_found != num_parts_opt && (!(alter_info->flags & ALTER_ALL_PARTITION))) { char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0e0e3ec6bd3..0610350b38f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3810,7 +3810,7 @@ partition_entry: ; partition: - BY part_type_def opt_no_parts opt_sub_part part_defs + BY part_type_def opt_num_parts opt_sub_part part_defs ; part_type_def: @@ -3895,20 +3895,20 @@ sub_part_func: ; -opt_no_parts: +opt_num_parts: /* empty */ {} | PARTITIONS_SYM real_ulong_num { - uint no_parts= $2; + uint num_parts= $2; partition_info *part_info= Lex->part_info; - if (no_parts == 0) + if (num_parts == 0) { my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions"); MYSQL_YYABORT; } - part_info->no_parts= no_parts; - part_info->use_default_no_partitions= FALSE; + part_info->num_parts= num_parts; + part_info->use_default_num_partitions= FALSE; } ; @@ -3916,7 +3916,7 @@ opt_sub_part: /* empty */ {} | SUBPARTITION_SYM BY opt_linear HASH_SYM sub_part_func { Lex->part_info->subpart_type= HASH_PARTITION; } - opt_no_subparts {} + opt_num_subparts {} | SUBPARTITION_SYM BY opt_linear KEY_SYM '(' sub_part_field_list ')' { @@ -3924,7 +3924,7 @@ opt_sub_part: part_info->subpart_type= HASH_PARTITION; part_info->list_of_subpart_fields= TRUE; } - opt_no_subparts {} + opt_num_subparts {} ; sub_part_field_list: @@ -3966,19 +3966,19 @@ part_func_expr: } ; -opt_no_subparts: +opt_num_subparts: /* empty */ {} | SUBPARTITIONS_SYM real_ulong_num { - uint no_parts= $2; + uint num_parts= $2; LEX *lex= Lex; - if (no_parts == 0) + if (num_parts == 0) { my_error(ER_NO_PARTS_ERROR, MYF(0), "subpartitions"); MYSQL_YYABORT; } - lex->part_info->no_subparts= no_parts; - lex->part_info->use_default_no_subpartitions= FALSE; + lex->part_info->num_subparts= num_parts; + lex->part_info->use_default_num_subpartitions= FALSE; } ; @@ -3989,9 +3989,9 @@ part_defs: { partition_info *part_info= Lex->part_info; uint count_curr_parts= part_info->partitions.elements; - if (part_info->no_parts != 0) + if (part_info->num_parts != 0) { - if (part_info->no_parts != + if (part_info->num_parts != count_curr_parts) { my_parse_error(ER(ER_PARTITION_WRONG_NO_PART_ERROR)); @@ -4000,7 +4000,7 @@ part_defs: } else if (count_curr_parts > 0) { - part_info->no_parts= count_curr_parts; + part_info->num_parts= count_curr_parts; } part_info->count_curr_subparts= 0; } @@ -4026,7 +4026,7 @@ part_definition: part_info->curr_part_elem= p_elem; part_info->current_partition= p_elem; part_info->use_default_partitions= FALSE; - part_info->use_default_no_partitions= FALSE; + part_info->use_default_num_partitions= FALSE; } part_name opt_part_values @@ -4338,7 +4338,7 @@ opt_sub_partition: /* empty */ { partition_info *part_info= Lex->part_info; - if (part_info->no_subparts != 0 && + if (part_info->num_subparts != 0 && !part_info->use_default_subpartitions) { /* @@ -4352,9 +4352,9 @@ opt_sub_partition: | '(' sub_part_list ')' { partition_info *part_info= Lex->part_info; - if (part_info->no_subparts != 0) + if (part_info->num_subparts != 0) { - if (part_info->no_subparts != + if (part_info->num_subparts != part_info->count_curr_subparts) { my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR)); @@ -4368,7 +4368,7 @@ opt_sub_partition: my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR)); MYSQL_YYABORT; } - part_info->no_subparts= part_info->count_curr_subparts; + part_info->num_subparts= part_info->count_curr_subparts; } part_info->count_curr_subparts= 0; } @@ -4410,7 +4410,7 @@ sub_part_definition: } part_info->curr_part_elem= sub_p_elem; part_info->use_default_subpartitions= FALSE; - part_info->use_default_no_subpartitions= FALSE; + part_info->use_default_num_subpartitions= FALSE; part_info->count_curr_subparts++; } sub_name opt_part_options {} @@ -5850,7 +5850,7 @@ alter_commands: LEX *lex= Lex; lex->alter_info.flags|= ALTER_COALESCE_PARTITION; lex->no_write_to_binlog= $3; - lex->alter_info.no_parts= $4; + lex->alter_info.num_parts= $4; } | reorg_partition_rule ; @@ -5892,12 +5892,11 @@ add_part_extra: | '(' part_def_list ')' { LEX *lex= Lex; - lex->part_info->no_parts= lex->part_info->partitions.elements; + lex->part_info->num_parts= lex->part_info->partitions.elements; } | PARTITIONS_SYM real_ulong_num { - LEX *lex= Lex; - lex->part_info->no_parts= $2; + Lex->part_info->num_parts= $2; } ; @@ -5928,7 +5927,7 @@ reorg_parts_rule: INTO '(' part_def_list ')' { partition_info *part_info= Lex->part_info; - part_info->no_parts= part_info->partitions.elements; + part_info->num_parts= part_info->partitions.elements; } ; From 66ea81cdb1f6499d8661d6f0c0750218bcb326c5 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 1 Oct 2009 15:09:20 +0200 Subject: [PATCH 055/274] BUG#47752, missed to sort values in list partitioning --- sql/partition_info.cc | 7 ++++--- sql/sql_partition.cc | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index aaa6d0d3767..0540c094ccc 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -993,15 +993,16 @@ bool partition_info::check_list_constants(THD *thd) } } while (++i < num_parts); } - if (fixed && num_list_values) + DBUG_ASSERT(fixed); + if (num_list_values) { bool first= TRUE; /* list_array and list_col_array are unions, so this works for both variants of LIST partitioning. */ - my_qsort((void*)list_array, num_list_values, sizeof(LIST_PART_ENTRY), - &list_part_cmp); + my_qsort((void*)list_array, num_list_values, size_entries, + compare_func); i= 0; LINT_INIT(prev_value); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 9a9618108e5..05b3822ce43 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1030,8 +1030,6 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, if ((!is_sub_part) && (error= check_signed_flag(part_info))) goto end; result= set_up_field_array(table, is_sub_part); - if (!is_sub_part) - part_info->fixed= TRUE; end: table->get_fields_in_item_tree= FALSE; table->map= 0; //Restore old value @@ -1667,6 +1665,7 @@ bool fix_partition_func(THD *thd, TABLE *table, } part_info->part_result_type= INT_RESULT; } + part_info->fixed= TRUE; } else { @@ -1683,6 +1682,7 @@ bool fix_partition_func(THD *thd, TABLE *table, table, FALSE))) goto end; } + part_info->fixed= TRUE; if (part_info->part_type == RANGE_PARTITION) { error_str= partition_keywords[PKW_RANGE].str; From 4d624635c58520e933f54e1e25b68c9c42e19816 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 1 Oct 2009 16:50:11 +0200 Subject: [PATCH 056/274] Added more test cases --- mysql-test/r/partition_column.result | 40 ++++++++++++++++++++++++++++ mysql-test/t/partition_column.test | 19 +++++++++++++ 2 files changed, 59 insertions(+) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 0aaa4e78f68..66308321a95 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,36 @@ drop table if exists t1; +create table t1 (a int, b int) +partition by list column_list(a,b) +( partition p0 values in (column_list(1, NULL), column_list(2, NULL), +column_list(NULL, NULL)), +partition p1 values in (column_list(1,1), column_list(2,2)), +partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +insert into t1 values (3, NULL); +insert into t1 values (NULL, 1); +insert into t1 values (NULL, NULL); +insert into t1 values (1, NULL); +insert into t1 values (2, NULL); +insert into t1 values (1,1); +insert into t1 values (2,2); +select * from t1 where a = 1; +a b +1 NULL +1 1 +select * from t1 where a = 2; +a b +2 NULL +2 2 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST COLUMN_LIST(a,b) +(PARTITION p0 VALUES IN ( COLUMN_LIST(1,NULL), COLUMN_LIST(2,NULL), COLUMN_LIST(NULL,NULL)) ENGINE = MyISAM, + PARTITION p1 VALUES IN ( COLUMN_LIST(1,1), COLUMN_LIST(2,2)) ENGINE = MyISAM, + PARTITION p2 VALUES IN ( COLUMN_LIST(3,NULL), COLUMN_LIST(NULL,1)) ENGINE = MyISAM) */ +drop table t1; create table t1 (a int) partition by list (a) ( partition p0 values in (1), @@ -27,6 +59,14 @@ insert into t1 values (4); insert into t1 values (NULL); insert into t1 values (5); ERROR HY000: Table has no partition for value from column_list +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST COLUMN_LIST(a) +(PARTITION p0 VALUES IN ( COLUMN_LIST(2), COLUMN_LIST(1)) ENGINE = MyISAM, + PARTITION p1 VALUES IN ( COLUMN_LIST(4), COLUMN_LIST(NULL), COLUMN_LIST(3)) ENGINE = MyISAM) */ drop table t1; create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index f551b58119e..ff625acdb1d 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,24 @@ drop table if exists t1; --enable_warnings +create table t1 (a int, b int) +partition by list column_list(a,b) +( partition p0 values in (column_list(1, NULL), column_list(2, NULL), + column_list(NULL, NULL)), + partition p1 values in (column_list(1,1), column_list(2,2)), + partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +insert into t1 values (3, NULL); +insert into t1 values (NULL, 1); +insert into t1 values (NULL, NULL); +insert into t1 values (1, NULL); +insert into t1 values (2, NULL); +insert into t1 values (1,1); +insert into t1 values (2,2); +select * from t1 where a = 1; +select * from t1 where a = 2; +show create table t1; +drop table t1; + --error ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR create table t1 (a int) partition by list (a) @@ -38,6 +56,7 @@ insert into t1 values (4); insert into t1 values (NULL); --error ER_NO_PARTITION_FOR_GIVEN_VALUE insert into t1 values (5); +show create table t1; drop table t1; create table t1 (a int, b char(10), c varchar(25), d datetime) From d0627362adee94d0cac63426a045365f8d8109fd Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 1 Oct 2009 17:15:50 +0200 Subject: [PATCH 057/274] Fixed no_ to num_ change for NDB handler --- sql/ha_ndbcluster.cc | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 264e5649ea9..0aea0128819 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -9781,7 +9781,7 @@ void ha_ndbcluster::set_auto_partitions(partition_info *part_info) int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) { NDBTAB *tab= (NDBTAB*)tab_ref; - int32 *range_data= (int32*)my_malloc(part_info->no_parts*sizeof(int32), + int32 *range_data= (int32*)my_malloc(part_info->num_parts*sizeof(int32), MYF(0)); uint i; int error= 0; @@ -9790,17 +9790,17 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) if (!range_data) { - mem_alloc_error(part_info->no_parts*sizeof(int32)); + mem_alloc_error(part_info->num_parts*sizeof(int32)); DBUG_RETURN(1); } - for (i= 0; i < part_info->no_parts; i++) + for (i= 0; i < part_info->num_parts; i++) { longlong range_val= part_info->range_int_array[i]; if (unsigned_flag) range_val-= 0x8000000000000000ULL; if (range_val < INT_MIN32 || range_val >= INT_MAX32) { - if ((i != part_info->no_parts - 1) || + if ((i != part_info->num_parts - 1) || (range_val != LONGLONG_MAX)) { my_error(ER_LIMITED_PART_RANGE, MYF(0), "NDB"); @@ -9811,7 +9811,7 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) } range_data[i]= (int32)range_val; } - tab->setRangeListData(range_data, sizeof(int32)*part_info->no_parts); + tab->setRangeListData(range_data, sizeof(int32)*part_info->num_parts); error: my_free((char*)range_data, MYF(0)); DBUG_RETURN(error); @@ -9820,7 +9820,7 @@ error: int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) { NDBTAB *tab= (NDBTAB*)tab_ref; - int32 *list_data= (int32*)my_malloc(part_info->no_list_values * 2 + int32 *list_data= (int32*)my_malloc(part_info->num_list_values * 2 * sizeof(int32), MYF(0)); uint32 *part_id, i; int error= 0; @@ -9829,10 +9829,10 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) if (!list_data) { - mem_alloc_error(part_info->no_list_values*2*sizeof(int32)); + mem_alloc_error(part_info->num_list_values*2*sizeof(int32)); DBUG_RETURN(1); } - for (i= 0; i < part_info->no_list_values; i++) + for (i= 0; i < part_info->num_list_values; i++) { LIST_PART_ENTRY *list_entry= &part_info->list_array[i]; longlong list_val= list_entry->list_value; @@ -9848,7 +9848,7 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) part_id= (uint32*)&list_data[2*i+1]; *part_id= list_entry->partition_id; } - tab->setRangeListData(list_data, 2*sizeof(int32)*part_info->no_list_values); + tab->setRangeListData(list_data, 2*sizeof(int32)*part_info->num_list_values); error: my_free((char*)list_data, MYF(0)); DBUG_RETURN(error); @@ -9970,11 +9970,11 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info, ng= 0; ts_names[fd_index]= part_elem->tablespace_name; frag_data[fd_index++]= ng; - } while (++j < part_info->no_subparts); + } while (++j < part_info->num_subparts); } first= FALSE; - } while (++i < part_info->no_parts); - tab->setDefaultNoPartitionsFlag(part_info->use_default_no_partitions); + } while (++i < part_info->num_parts); + tab->setDefaultNoPartitionsFlag(part_info->use_default_num_partitions); tab->setLinearFlag(part_info->linear_hash_ind); { ha_rows max_rows= table_share->max_rows; @@ -10368,7 +10368,7 @@ ndberror2: } -bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts) +bool ha_ndbcluster::get_no_parts(const char *name, uint *num_parts) { Ndb *ndb; NDBDICT *dict; @@ -10390,7 +10390,7 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts) Ndb_table_guard ndbtab_g(dict= ndb->getDictionary(), m_tabname); if (!ndbtab_g.get_table()) ERR_BREAK(dict->getNdbError(), err); - *no_parts= ndbtab_g.get_table()->getFragmentCount(); + *num_parts= ndbtab_g.get_table()->getFragmentCount(); DBUG_RETURN(FALSE); } From d91aa57c38e9baf0bbf31a596e79bea2504e50bb Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 1 Oct 2009 19:44:53 +0300 Subject: [PATCH 058/274] backporting bug@27808 fixes --- mysql-test/include/master-slave.inc | 2 + mysql-test/r/ctype_cp932_binlog_stm.result | 14 +- .../r/flush_block_commit_notembedded.result | 4 +- mysql-test/r/multi_update.result | 4 +- mysql-test/r/outfile_loaddata.result | 20 +- mysql-test/r/strict.result | 2 +- .../suite/binlog/r/binlog_row_binlog.result | 37 +- .../suite/binlog/r/binlog_stm_binlog.result | 844 +++++++++--------- .../suite/binlog/t/binlog_incident.test | 4 +- mysql-test/suite/rpl/r/rpl_000015.result | 6 + mysql-test/suite/rpl/r/rpl_bug33931.result | 2 + .../suite/rpl/r/rpl_change_master.result | 4 + .../suite/rpl/r/rpl_deadlock_innodb.result | 6 + .../suite/rpl/r/rpl_extraCol_innodb.result | 20 + .../suite/rpl/r/rpl_extraCol_myisam.result | 20 + .../rpl/r/rpl_extraColmaster_innodb.result | 42 + .../rpl/r/rpl_extraColmaster_myisam.result | 42 + .../suite/rpl/r/rpl_flushlog_loop.result | 2 + mysql-test/suite/rpl/r/rpl_grant.result | 2 + mysql-test/suite/rpl/r/rpl_heartbeat.result | 4 + mysql-test/suite/rpl/r/rpl_incident.result | 4 + .../rpl/r/rpl_known_bugs_detection.result | 4 + mysql-test/suite/rpl/r/rpl_loaddata.result | 6 + .../suite/rpl/r/rpl_loaddata_fatal.result | 4 + mysql-test/suite/rpl/r/rpl_log_pos.result | 4 + mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result | 2 + .../suite/rpl/r/rpl_replicate_do.result | 2 + mysql-test/suite/rpl/r/rpl_rotate_logs.result | 6 + mysql-test/suite/rpl/r/rpl_row_colSize.result | 26 + mysql-test/suite/rpl/r/rpl_row_log.result | 2 + .../suite/rpl/r/rpl_row_log_innodb.result | 2 + .../suite/rpl/r/rpl_row_max_relay_size.result | 12 + .../suite/rpl/r/rpl_row_reset_slave.result | 8 + .../rpl/r/rpl_row_tabledefs_2myisam.result | 12 + .../rpl/r/rpl_row_tabledefs_3innodb.result | 12 + mysql-test/suite/rpl/r/rpl_row_until.result | 8 + mysql-test/suite/rpl/r/rpl_skip_error.result | 4 + .../r/rpl_slave_load_remove_tmpfile.result | 2 + mysql-test/suite/rpl/r/rpl_slave_skip.result | 4 + mysql-test/suite/rpl/r/rpl_ssl.result | 4 + mysql-test/suite/rpl/r/rpl_ssl1.result | 6 + mysql-test/suite/rpl/r/rpl_stm_log.result | 2 + .../suite/rpl/r/rpl_stm_max_relay_size.result | 12 + .../suite/rpl/r/rpl_stm_reset_slave.result | 8 + mysql-test/suite/rpl/r/rpl_stm_until.result | 8 + .../suite/rpl/r/rpl_temporary_errors.result | 2 + .../suite/rpl_ndb/r/rpl_ndb_basic.result | 2 + .../suite/rpl_ndb/r/rpl_ndb_circular.result | 4 + .../rpl_ndb/r/rpl_ndb_circular_simplex.result | 4 + .../suite/rpl_ndb/r/rpl_ndb_extraCol.result | 20 + .../suite/rpl_ndb/r/rpl_ndb_idempotent.result | 12 +- .../suite/rpl_ndb/r/rpl_ndb_sync.result | 2 + mysql-test/t/ctype_cp932_binlog_stm.test | 2 +- mysql-test/t/mysqlbinlog.test | 2 +- sql/lex.h | 1 + sql/rpl_mi.cc | 88 +- sql/rpl_mi.h | 9 +- sql/share/errmsg.txt | 3 + sql/slave.cc | 160 +++- sql/sql_lex.h | 3 +- sql/sql_repl.cc | 58 +- sql/sql_yacc.yy | 23 + 62 files changed, 1127 insertions(+), 513 deletions(-) diff --git a/mysql-test/include/master-slave.inc b/mysql-test/include/master-slave.inc index e0eb87f02f7..25e0150dd0a 100644 --- a/mysql-test/include/master-slave.inc +++ b/mysql-test/include/master-slave.inc @@ -8,5 +8,7 @@ connect (slave1,127.0.0.1,root,,test,$SLAVE_MYPORT,); -- source include/master-slave-reset.inc +connection master; +sync_slave_with_master; # Set the default connection to 'master' connection master; diff --git a/mysql-test/r/ctype_cp932_binlog_stm.result b/mysql-test/r/ctype_cp932_binlog_stm.result index 044885d1ea7..bb971e5453b 100644 --- a/mysql-test/r/ctype_cp932_binlog_stm.result +++ b/mysql-test/r/ctype_cp932_binlog_stm.result @@ -29,22 +29,22 @@ HEX(s1) HEX(s2) d 466F6F2773206120426172 ED40ED41ED42 47.93 DROP PROCEDURE bug18293| DROP TABLE t4| -SHOW BINLOG EVENTS FROM 370| +SHOW BINLOG EVENTS FROM 371| Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 370 Query 1 536 use `test`; CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1, +master-bin.000001 371 Query 1 537 use `test`; CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1, s2 CHAR(50) CHARACTER SET cp932, d DECIMAL(10,2)) -master-bin.000001 536 Query 1 785 use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `bug18293`(IN ins1 CHAR(50), +master-bin.000001 537 Query 1 786 use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `bug18293`(IN ins1 CHAR(50), IN ins2 CHAR(50) CHARACTER SET cp932, IN ind DECIMAL(10,2)) BEGIN INSERT INTO t4 VALUES (ins1, ins2, ind); END -master-bin.000001 785 Query 1 1049 use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1 0x466F6F2773206120426172 COLLATE 'latin1_swedish_ci'), NAME_CONST('ins2',_cp932 0xED40ED41ED42 COLLATE 'cp932_japanese_ci'), NAME_CONST('ind',47.93)) -master-bin.000001 1049 Query 1 1138 use `test`; DROP PROCEDURE bug18293 -master-bin.000001 1138 Query 1 1217 use `test`; DROP TABLE t4 +master-bin.000001 786 Query 1 1050 use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1 0x466F6F2773206120426172 COLLATE 'latin1_swedish_ci'), NAME_CONST('ins2',_cp932 0xED40ED41ED42 COLLATE 'cp932_japanese_ci'), NAME_CONST('ind',47.93)) +master-bin.000001 1050 Query 1 1139 use `test`; DROP PROCEDURE bug18293 +master-bin.000001 1139 Query 1 1218 use `test`; DROP TABLE t4 End of 5.0 tests -SHOW BINLOG EVENTS FROM 365; +SHOW BINLOG EVENTS FROM 366; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Wrong offset or I/O error Bug#44352 UPPER/LOWER function doesn't work correctly on cp932 and sjis environment. CREATE TABLE t1 (a varchar(16)) character set cp932; diff --git a/mysql-test/r/flush_block_commit_notembedded.result b/mysql-test/r/flush_block_commit_notembedded.result index c7fd7a11877..4348dbd67e5 100644 --- a/mysql-test/r/flush_block_commit_notembedded.result +++ b/mysql-test/r/flush_block_commit_notembedded.result @@ -9,13 +9,13 @@ INSERT t1 VALUES (1); FLUSH TABLES WITH READ LOCK; SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 106 +master-bin.000001 107 # Switch to connection con1 COMMIT; # Switch to connection con2 SHOW MASTER STATUS; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 106 +master-bin.000001 107 UNLOCK TABLES; # Switch to connection con1 DROP TABLE t1; diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 449333a4ae6..4f22029814c 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -604,7 +604,7 @@ a b 4 4 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 206 +master-bin.000001 207 delete from t1; delete from t2; insert into t1 values (1,2),(3,4),(4,4); @@ -614,7 +614,7 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; ERROR 23000: Duplicate entry '4' for key 'PRIMARY' show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 221 +master-bin.000001 222 drop table t1, t2; set @@session.binlog_format= @sav_binlog_format; drop table if exists t1, t2, t3; diff --git a/mysql-test/r/outfile_loaddata.result b/mysql-test/r/outfile_loaddata.result index 453e3adb54c..66ff28298ba 100644 --- a/mysql-test/r/outfile_loaddata.result +++ b/mysql-test/r/outfile_loaddata.result @@ -92,14 +92,14 @@ HEX(c1) C3 SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug32533.txt' FIELDS ENCLOSED BY 0xC3 FROM t1; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported TRUNCATE t1; SELECT HEX(LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug32533.txt')); HEX(LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug32533.txt')) C35CC3C30A LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug32533.txt' INTO TABLE t1 FIELDS ENCLOSED BY 0xC3; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported SELECT HEX(c1) FROM t1; HEX(c1) C3 @@ -124,17 +124,17 @@ ERROR 42000: Field separator argument is not what is expected; check the manual # LOAD DATA rises error or has unpredictable result -- to be fixed later SELECT * FROM t1 INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' FIELDS ENCLOSED BY 'ÑŠ'; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' INTO TABLE t2 CHARACTER SET binary FIELDS ENCLOSED BY 'ÑŠ'; ERROR 42000: Field separator argument is not what is expected; check the manual SELECT * FROM t1 INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' FIELDS ESCAPED BY 'ÑŠ'; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' INTO TABLE t2 CHARACTER SET binary FIELDS ESCAPED BY 'ÑŠ'; ERROR 42000: Field separator argument is not what is expected; check the manual SELECT * FROM t1 INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' FIELDS TERMINATED BY 'ÑŠ'; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported ################################################## 1ÑŠABC-áâ÷ÑŠDEF-ÂÃÄ 2ÑŠ\NÑŠ\N @@ -142,7 +142,7 @@ Warning 1638 Non-ASCII separator arguments are not fully supported TRUNCATE t2; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' INTO TABLE t2 CHARACTER SET binary FIELDS TERMINATED BY 'ÑŠ'; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported Warning 1265 Data truncated for column 'a' at row 1 Warning 1261 Row 1 doesn't contain data for all columns Warning 1261 Row 1 doesn't contain data for all columns @@ -156,7 +156,7 @@ a b c 2 NULL NULL SELECT * FROM t1 INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' LINES STARTING BY 'ÑŠ'; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported ################################################## ÑŠ1 ABC-áâ÷ DEF-ÂÃÄ ÑŠ2 \N \N @@ -164,20 +164,20 @@ Warning 1638 Non-ASCII separator arguments are not fully supported TRUNCATE t2; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' INTO TABLE t2 CHARACTER SET binary LINES STARTING BY 'ÑŠ'; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a, b, c; a b c 1 ABC-ÐБВ DEF-ÂÃÄ 2 NULL NULL SELECT * FROM t1 INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' LINES TERMINATED BY 'ÑŠ'; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported ################################################## 1 ABC-áâ÷ DEF-ÂÃÄÑŠ2 \N \NÑŠ################################################## TRUNCATE t2; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' INTO TABLE t2 CHARACTER SET binary LINES TERMINATED BY 'ÑŠ'; Warnings: -Warning 1638 Non-ASCII separator arguments are not fully supported +Warning 1639 Non-ASCII separator arguments are not fully supported SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a, b, c; a b c 1 ABC-ÐБВ DEF-ÂÃÄ diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index 241f4198bf7..b11f60792ef 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -1327,7 +1327,7 @@ create table t1 123456789*123456789*123456789*123456789* 123456789*123456789*123456789*123456789*'); Warnings: -Warning 1629 Comment for field 'i' is too long (max = 255) +Warning 1630 Comment for field 'i' is too long (max = 255) select column_name, column_comment from information_schema.columns where table_schema = 'test' and table_name = 't1'; column_name column_comment diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index d2d702b12a0..d6d6c99f00a 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -247,25 +247,8 @@ commit; drop table t1; show binlog events from 0; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4 -master-bin.000001 106 Query 1 205 use `test`; create table t1(n int) engine=innodb -master-bin.000001 205 Query 1 273 BEGIN -master-bin.000001 273 Table_map 1 314 table_id: # (test.t1) -master-bin.000001 314 Write_rows 1 348 table_id: # flags: STMT_END_F -master-bin.000001 348 Table_map 1 389 table_id: # (test.t1) -master-bin.000001 389 Write_rows 1 423 table_id: # flags: STMT_END_F -master-bin.000001 423 Table_map 1 464 table_id: # (test.t1) -master-bin.000001 464 Write_rows 1 498 table_id: # flags: STMT_END_F -master-bin.000001 498 Xid 1 525 COMMIT /* XID */ -master-bin.000001 525 Query 1 601 use `test`; drop table t1 -set @bcs = @@binlog_cache_size; -set global binlog_cache_size=4096; -reset master; -create table t1 (a int) engine=innodb; -show binlog events from 0; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4 -master-bin.000001 106 Query 1 206 use `test`; create table t1 (a int) engine=innodb +master-bin.000001 4 Format_desc 1 107 Server version, Binlog ver: 4 +master-bin.000001 107 Query 1 206 use `test`; create table t1(n int) engine=innodb master-bin.000001 206 Query 1 274 BEGIN master-bin.000001 274 Table_map 1 315 table_id: # (test.t1) master-bin.000001 315 Write_rows 1 349 table_id: # flags: STMT_END_F @@ -283,7 +266,7 @@ show binlog events from 0; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 107 Server version, Binlog ver: 4 master-bin.000001 107 Query 1 207 use `test`; create table t1 (a int) engine=innodb -master-bin.000001 207 Query 1 275 use `test`; BEGIN +master-bin.000001 207 Query 1 275 BEGIN master-bin.000001 275 Table_map 1 316 table_id: # (test.t1) master-bin.000001 316 Write_rows 1 350 table_id: # flags: STMT_END_F master-bin.000001 350 Table_map 1 391 table_id: # (test.t1) @@ -1100,13 +1083,13 @@ deallocate prepare stmt; drop table t1; show binlog events from 0; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4 -master-bin.000001 106 Query 1 227 use `test`; create table t1 (a bigint unsigned, b bigint(20) unsigned) -master-bin.000001 227 Query 1 295 BEGIN -master-bin.000001 295 Table_map 1 337 table_id: # (test.t1) -master-bin.000001 337 Write_rows 1 383 table_id: # flags: STMT_END_F -master-bin.000001 383 Query 1 452 COMMIT -master-bin.000001 452 Query 1 528 use `test`; drop table t1 +master-bin.000001 4 Format_desc 1 107 Server version, Binlog ver: 4 +master-bin.000001 107 Query 1 228 use `test`; create table t1 (a bigint unsigned, b bigint(20) unsigned) +master-bin.000001 228 Query 1 296 BEGIN +master-bin.000001 296 Table_map 1 338 table_id: # (test.t1) +master-bin.000001 338 Write_rows 1 384 table_id: # flags: STMT_END_F +master-bin.000001 384 Query 1 453 COMMIT +master-bin.000001 453 Query 1 529 use `test`; drop table t1 reset master; CREATE DATABASE bug39182 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; USE bug39182; diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index 9df4164b138..c0a87be191b 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -4,11 +4,11 @@ insert into t1 values (1,2); commit; show binlog events; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server ver: #, Binlog ver: # -master-bin.000001 106 Query 1 213 use `test`; create table t1 (a int, b int) engine=innodb -master-bin.000001 213 Query 1 281 BEGIN -master-bin.000001 281 Query 1 371 use `test`; insert into t1 values (1,2) -master-bin.000001 371 Xid 1 398 COMMIT /* XID */ +master-bin.000001 4 Format_desc 1 107 Server ver: #, Binlog ver: # +master-bin.000001 107 Query 1 214 use `test`; create table t1 (a int, b int) engine=innodb +master-bin.000001 214 Query 1 282 BEGIN +master-bin.000001 282 Query 1 372 use `test`; insert into t1 values (1,2) +master-bin.000001 372 Xid 1 399 COMMIT /* XID */ drop table t1; drop table if exists t1, t2; reset master; @@ -157,425 +157,425 @@ commit; drop table t1; show binlog events from 0; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4 -master-bin.000001 106 Query 1 205 use `test`; create table t1(n int) engine=innodb -master-bin.000001 205 Query 1 273 BEGIN -master-bin.000001 273 Query 1 361 use `test`; insert into t1 values (1) -master-bin.000001 361 Query 1 449 use `test`; insert into t1 values (2) -master-bin.000001 449 Query 1 537 use `test`; insert into t1 values (3) -master-bin.000001 537 Xid 1 564 COMMIT /* XID */ -master-bin.000001 564 Query 1 640 use `test`; drop table t1 +master-bin.000001 4 Format_desc 1 107 Server version, Binlog ver: 4 +master-bin.000001 107 Query 1 206 use `test`; create table t1(n int) engine=innodb +master-bin.000001 206 Query 1 274 BEGIN +master-bin.000001 274 Query 1 362 use `test`; insert into t1 values (1) +master-bin.000001 362 Query 1 450 use `test`; insert into t1 values (2) +master-bin.000001 450 Query 1 538 use `test`; insert into t1 values (3) +master-bin.000001 538 Xid 1 565 COMMIT /* XID */ +master-bin.000001 565 Query 1 641 use `test`; drop table t1 set @bcs = @@binlog_cache_size; set global binlog_cache_size=4096; reset master; create table t1 (a int) engine=innodb; show binlog events from 0; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4 -master-bin.000001 106 Query 1 206 use `test`; create table t1 (a int) engine=innodb -master-bin.000001 206 Query 1 274 BEGIN -master-bin.000001 274 Query 1 365 use `test`; insert into t1 values( 400 ) -master-bin.000001 365 Query 1 456 use `test`; insert into t1 values( 399 ) -master-bin.000001 456 Query 1 547 use `test`; insert into t1 values( 398 ) -master-bin.000001 547 Query 1 638 use `test`; insert into t1 values( 397 ) -master-bin.000001 638 Query 1 729 use `test`; insert into t1 values( 396 ) -master-bin.000001 729 Query 1 820 use `test`; insert into t1 values( 395 ) -master-bin.000001 820 Query 1 911 use `test`; insert into t1 values( 394 ) -master-bin.000001 911 Query 1 1002 use `test`; insert into t1 values( 393 ) -master-bin.000001 1002 Query 1 1093 use `test`; insert into t1 values( 392 ) -master-bin.000001 1093 Query 1 1184 use `test`; insert into t1 values( 391 ) -master-bin.000001 1184 Query 1 1275 use `test`; insert into t1 values( 390 ) -master-bin.000001 1275 Query 1 1366 use `test`; insert into t1 values( 389 ) -master-bin.000001 1366 Query 1 1457 use `test`; insert into t1 values( 388 ) -master-bin.000001 1457 Query 1 1548 use `test`; insert into t1 values( 387 ) -master-bin.000001 1548 Query 1 1639 use `test`; insert into t1 values( 386 ) -master-bin.000001 1639 Query 1 1730 use `test`; insert into t1 values( 385 ) -master-bin.000001 1730 Query 1 1821 use `test`; insert into t1 values( 384 ) -master-bin.000001 1821 Query 1 1912 use `test`; insert into t1 values( 383 ) -master-bin.000001 1912 Query 1 2003 use `test`; insert into t1 values( 382 ) -master-bin.000001 2003 Query 1 2094 use `test`; insert into t1 values( 381 ) -master-bin.000001 2094 Query 1 2185 use `test`; insert into t1 values( 380 ) -master-bin.000001 2185 Query 1 2276 use `test`; insert into t1 values( 379 ) -master-bin.000001 2276 Query 1 2367 use `test`; insert into t1 values( 378 ) -master-bin.000001 2367 Query 1 2458 use `test`; insert into t1 values( 377 ) -master-bin.000001 2458 Query 1 2549 use `test`; insert into t1 values( 376 ) -master-bin.000001 2549 Query 1 2640 use `test`; insert into t1 values( 375 ) -master-bin.000001 2640 Query 1 2731 use `test`; insert into t1 values( 374 ) -master-bin.000001 2731 Query 1 2822 use `test`; insert into t1 values( 373 ) -master-bin.000001 2822 Query 1 2913 use `test`; insert into t1 values( 372 ) -master-bin.000001 2913 Query 1 3004 use `test`; insert into t1 values( 371 ) -master-bin.000001 3004 Query 1 3095 use `test`; insert into t1 values( 370 ) -master-bin.000001 3095 Query 1 3186 use `test`; insert into t1 values( 369 ) -master-bin.000001 3186 Query 1 3277 use `test`; insert into t1 values( 368 ) -master-bin.000001 3277 Query 1 3368 use `test`; insert into t1 values( 367 ) -master-bin.000001 3368 Query 1 3459 use `test`; insert into t1 values( 366 ) -master-bin.000001 3459 Query 1 3550 use `test`; insert into t1 values( 365 ) -master-bin.000001 3550 Query 1 3641 use `test`; insert into t1 values( 364 ) -master-bin.000001 3641 Query 1 3732 use `test`; insert into t1 values( 363 ) -master-bin.000001 3732 Query 1 3823 use `test`; insert into t1 values( 362 ) -master-bin.000001 3823 Query 1 3914 use `test`; insert into t1 values( 361 ) -master-bin.000001 3914 Query 1 4005 use `test`; insert into t1 values( 360 ) -master-bin.000001 4005 Query 1 4096 use `test`; insert into t1 values( 359 ) -master-bin.000001 4096 Query 1 4187 use `test`; insert into t1 values( 358 ) -master-bin.000001 4187 Query 1 4278 use `test`; insert into t1 values( 357 ) -master-bin.000001 4278 Query 1 4369 use `test`; insert into t1 values( 356 ) -master-bin.000001 4369 Query 1 4460 use `test`; insert into t1 values( 355 ) -master-bin.000001 4460 Query 1 4551 use `test`; insert into t1 values( 354 ) -master-bin.000001 4551 Query 1 4642 use `test`; insert into t1 values( 353 ) -master-bin.000001 4642 Query 1 4733 use `test`; insert into t1 values( 352 ) -master-bin.000001 4733 Query 1 4824 use `test`; insert into t1 values( 351 ) -master-bin.000001 4824 Query 1 4915 use `test`; insert into t1 values( 350 ) -master-bin.000001 4915 Query 1 5006 use `test`; insert into t1 values( 349 ) -master-bin.000001 5006 Query 1 5097 use `test`; insert into t1 values( 348 ) -master-bin.000001 5097 Query 1 5188 use `test`; insert into t1 values( 347 ) -master-bin.000001 5188 Query 1 5279 use `test`; insert into t1 values( 346 ) -master-bin.000001 5279 Query 1 5370 use `test`; insert into t1 values( 345 ) -master-bin.000001 5370 Query 1 5461 use `test`; insert into t1 values( 344 ) -master-bin.000001 5461 Query 1 5552 use `test`; insert into t1 values( 343 ) -master-bin.000001 5552 Query 1 5643 use `test`; insert into t1 values( 342 ) -master-bin.000001 5643 Query 1 5734 use `test`; insert into t1 values( 341 ) -master-bin.000001 5734 Query 1 5825 use `test`; insert into t1 values( 340 ) -master-bin.000001 5825 Query 1 5916 use `test`; insert into t1 values( 339 ) -master-bin.000001 5916 Query 1 6007 use `test`; insert into t1 values( 338 ) -master-bin.000001 6007 Query 1 6098 use `test`; insert into t1 values( 337 ) -master-bin.000001 6098 Query 1 6189 use `test`; insert into t1 values( 336 ) -master-bin.000001 6189 Query 1 6280 use `test`; insert into t1 values( 335 ) -master-bin.000001 6280 Query 1 6371 use `test`; insert into t1 values( 334 ) -master-bin.000001 6371 Query 1 6462 use `test`; insert into t1 values( 333 ) -master-bin.000001 6462 Query 1 6553 use `test`; insert into t1 values( 332 ) -master-bin.000001 6553 Query 1 6644 use `test`; insert into t1 values( 331 ) -master-bin.000001 6644 Query 1 6735 use `test`; insert into t1 values( 330 ) -master-bin.000001 6735 Query 1 6826 use `test`; insert into t1 values( 329 ) -master-bin.000001 6826 Query 1 6917 use `test`; insert into t1 values( 328 ) -master-bin.000001 6917 Query 1 7008 use `test`; insert into t1 values( 327 ) -master-bin.000001 7008 Query 1 7099 use `test`; insert into t1 values( 326 ) -master-bin.000001 7099 Query 1 7190 use `test`; insert into t1 values( 325 ) -master-bin.000001 7190 Query 1 7281 use `test`; insert into t1 values( 324 ) -master-bin.000001 7281 Query 1 7372 use `test`; insert into t1 values( 323 ) -master-bin.000001 7372 Query 1 7463 use `test`; insert into t1 values( 322 ) -master-bin.000001 7463 Query 1 7554 use `test`; insert into t1 values( 321 ) -master-bin.000001 7554 Query 1 7645 use `test`; insert into t1 values( 320 ) -master-bin.000001 7645 Query 1 7736 use `test`; insert into t1 values( 319 ) -master-bin.000001 7736 Query 1 7827 use `test`; insert into t1 values( 318 ) -master-bin.000001 7827 Query 1 7918 use `test`; insert into t1 values( 317 ) -master-bin.000001 7918 Query 1 8009 use `test`; insert into t1 values( 316 ) -master-bin.000001 8009 Query 1 8100 use `test`; insert into t1 values( 315 ) -master-bin.000001 8100 Query 1 8191 use `test`; insert into t1 values( 314 ) -master-bin.000001 8191 Query 1 8282 use `test`; insert into t1 values( 313 ) -master-bin.000001 8282 Query 1 8373 use `test`; insert into t1 values( 312 ) -master-bin.000001 8373 Query 1 8464 use `test`; insert into t1 values( 311 ) -master-bin.000001 8464 Query 1 8555 use `test`; insert into t1 values( 310 ) -master-bin.000001 8555 Query 1 8646 use `test`; insert into t1 values( 309 ) -master-bin.000001 8646 Query 1 8737 use `test`; insert into t1 values( 308 ) -master-bin.000001 8737 Query 1 8828 use `test`; insert into t1 values( 307 ) -master-bin.000001 8828 Query 1 8919 use `test`; insert into t1 values( 306 ) -master-bin.000001 8919 Query 1 9010 use `test`; insert into t1 values( 305 ) -master-bin.000001 9010 Query 1 9101 use `test`; insert into t1 values( 304 ) -master-bin.000001 9101 Query 1 9192 use `test`; insert into t1 values( 303 ) -master-bin.000001 9192 Query 1 9283 use `test`; insert into t1 values( 302 ) -master-bin.000001 9283 Query 1 9374 use `test`; insert into t1 values( 301 ) -master-bin.000001 9374 Query 1 9465 use `test`; insert into t1 values( 300 ) -master-bin.000001 9465 Query 1 9556 use `test`; insert into t1 values( 299 ) -master-bin.000001 9556 Query 1 9647 use `test`; insert into t1 values( 298 ) -master-bin.000001 9647 Query 1 9738 use `test`; insert into t1 values( 297 ) -master-bin.000001 9738 Query 1 9829 use `test`; insert into t1 values( 296 ) -master-bin.000001 9829 Query 1 9920 use `test`; insert into t1 values( 295 ) -master-bin.000001 9920 Query 1 10011 use `test`; insert into t1 values( 294 ) -master-bin.000001 10011 Query 1 10102 use `test`; insert into t1 values( 293 ) -master-bin.000001 10102 Query 1 10193 use `test`; insert into t1 values( 292 ) -master-bin.000001 10193 Query 1 10284 use `test`; insert into t1 values( 291 ) -master-bin.000001 10284 Query 1 10375 use `test`; insert into t1 values( 290 ) -master-bin.000001 10375 Query 1 10466 use `test`; insert into t1 values( 289 ) -master-bin.000001 10466 Query 1 10557 use `test`; insert into t1 values( 288 ) -master-bin.000001 10557 Query 1 10648 use `test`; insert into t1 values( 287 ) -master-bin.000001 10648 Query 1 10739 use `test`; insert into t1 values( 286 ) -master-bin.000001 10739 Query 1 10830 use `test`; insert into t1 values( 285 ) -master-bin.000001 10830 Query 1 10921 use `test`; insert into t1 values( 284 ) -master-bin.000001 10921 Query 1 11012 use `test`; insert into t1 values( 283 ) -master-bin.000001 11012 Query 1 11103 use `test`; insert into t1 values( 282 ) -master-bin.000001 11103 Query 1 11194 use `test`; insert into t1 values( 281 ) -master-bin.000001 11194 Query 1 11285 use `test`; insert into t1 values( 280 ) -master-bin.000001 11285 Query 1 11376 use `test`; insert into t1 values( 279 ) -master-bin.000001 11376 Query 1 11467 use `test`; insert into t1 values( 278 ) -master-bin.000001 11467 Query 1 11558 use `test`; insert into t1 values( 277 ) -master-bin.000001 11558 Query 1 11649 use `test`; insert into t1 values( 276 ) -master-bin.000001 11649 Query 1 11740 use `test`; insert into t1 values( 275 ) -master-bin.000001 11740 Query 1 11831 use `test`; insert into t1 values( 274 ) -master-bin.000001 11831 Query 1 11922 use `test`; insert into t1 values( 273 ) -master-bin.000001 11922 Query 1 12013 use `test`; insert into t1 values( 272 ) -master-bin.000001 12013 Query 1 12104 use `test`; insert into t1 values( 271 ) -master-bin.000001 12104 Query 1 12195 use `test`; insert into t1 values( 270 ) -master-bin.000001 12195 Query 1 12286 use `test`; insert into t1 values( 269 ) -master-bin.000001 12286 Query 1 12377 use `test`; insert into t1 values( 268 ) -master-bin.000001 12377 Query 1 12468 use `test`; insert into t1 values( 267 ) -master-bin.000001 12468 Query 1 12559 use `test`; insert into t1 values( 266 ) -master-bin.000001 12559 Query 1 12650 use `test`; insert into t1 values( 265 ) -master-bin.000001 12650 Query 1 12741 use `test`; insert into t1 values( 264 ) -master-bin.000001 12741 Query 1 12832 use `test`; insert into t1 values( 263 ) -master-bin.000001 12832 Query 1 12923 use `test`; insert into t1 values( 262 ) -master-bin.000001 12923 Query 1 13014 use `test`; insert into t1 values( 261 ) -master-bin.000001 13014 Query 1 13105 use `test`; insert into t1 values( 260 ) -master-bin.000001 13105 Query 1 13196 use `test`; insert into t1 values( 259 ) -master-bin.000001 13196 Query 1 13287 use `test`; insert into t1 values( 258 ) -master-bin.000001 13287 Query 1 13378 use `test`; insert into t1 values( 257 ) -master-bin.000001 13378 Query 1 13469 use `test`; insert into t1 values( 256 ) -master-bin.000001 13469 Query 1 13560 use `test`; insert into t1 values( 255 ) -master-bin.000001 13560 Query 1 13651 use `test`; insert into t1 values( 254 ) -master-bin.000001 13651 Query 1 13742 use `test`; insert into t1 values( 253 ) -master-bin.000001 13742 Query 1 13833 use `test`; insert into t1 values( 252 ) -master-bin.000001 13833 Query 1 13924 use `test`; insert into t1 values( 251 ) -master-bin.000001 13924 Query 1 14015 use `test`; insert into t1 values( 250 ) -master-bin.000001 14015 Query 1 14106 use `test`; insert into t1 values( 249 ) -master-bin.000001 14106 Query 1 14197 use `test`; insert into t1 values( 248 ) -master-bin.000001 14197 Query 1 14288 use `test`; insert into t1 values( 247 ) -master-bin.000001 14288 Query 1 14379 use `test`; insert into t1 values( 246 ) -master-bin.000001 14379 Query 1 14470 use `test`; insert into t1 values( 245 ) -master-bin.000001 14470 Query 1 14561 use `test`; insert into t1 values( 244 ) -master-bin.000001 14561 Query 1 14652 use `test`; insert into t1 values( 243 ) -master-bin.000001 14652 Query 1 14743 use `test`; insert into t1 values( 242 ) -master-bin.000001 14743 Query 1 14834 use `test`; insert into t1 values( 241 ) -master-bin.000001 14834 Query 1 14925 use `test`; insert into t1 values( 240 ) -master-bin.000001 14925 Query 1 15016 use `test`; insert into t1 values( 239 ) -master-bin.000001 15016 Query 1 15107 use `test`; insert into t1 values( 238 ) -master-bin.000001 15107 Query 1 15198 use `test`; insert into t1 values( 237 ) -master-bin.000001 15198 Query 1 15289 use `test`; insert into t1 values( 236 ) -master-bin.000001 15289 Query 1 15380 use `test`; insert into t1 values( 235 ) -master-bin.000001 15380 Query 1 15471 use `test`; insert into t1 values( 234 ) -master-bin.000001 15471 Query 1 15562 use `test`; insert into t1 values( 233 ) -master-bin.000001 15562 Query 1 15653 use `test`; insert into t1 values( 232 ) -master-bin.000001 15653 Query 1 15744 use `test`; insert into t1 values( 231 ) -master-bin.000001 15744 Query 1 15835 use `test`; insert into t1 values( 230 ) -master-bin.000001 15835 Query 1 15926 use `test`; insert into t1 values( 229 ) -master-bin.000001 15926 Query 1 16017 use `test`; insert into t1 values( 228 ) -master-bin.000001 16017 Query 1 16108 use `test`; insert into t1 values( 227 ) -master-bin.000001 16108 Query 1 16199 use `test`; insert into t1 values( 226 ) -master-bin.000001 16199 Query 1 16290 use `test`; insert into t1 values( 225 ) -master-bin.000001 16290 Query 1 16381 use `test`; insert into t1 values( 224 ) -master-bin.000001 16381 Query 1 16472 use `test`; insert into t1 values( 223 ) -master-bin.000001 16472 Query 1 16563 use `test`; insert into t1 values( 222 ) -master-bin.000001 16563 Query 1 16654 use `test`; insert into t1 values( 221 ) -master-bin.000001 16654 Query 1 16745 use `test`; insert into t1 values( 220 ) -master-bin.000001 16745 Query 1 16836 use `test`; insert into t1 values( 219 ) -master-bin.000001 16836 Query 1 16927 use `test`; insert into t1 values( 218 ) -master-bin.000001 16927 Query 1 17018 use `test`; insert into t1 values( 217 ) -master-bin.000001 17018 Query 1 17109 use `test`; insert into t1 values( 216 ) -master-bin.000001 17109 Query 1 17200 use `test`; insert into t1 values( 215 ) -master-bin.000001 17200 Query 1 17291 use `test`; insert into t1 values( 214 ) -master-bin.000001 17291 Query 1 17382 use `test`; insert into t1 values( 213 ) -master-bin.000001 17382 Query 1 17473 use `test`; insert into t1 values( 212 ) -master-bin.000001 17473 Query 1 17564 use `test`; insert into t1 values( 211 ) -master-bin.000001 17564 Query 1 17655 use `test`; insert into t1 values( 210 ) -master-bin.000001 17655 Query 1 17746 use `test`; insert into t1 values( 209 ) -master-bin.000001 17746 Query 1 17837 use `test`; insert into t1 values( 208 ) -master-bin.000001 17837 Query 1 17928 use `test`; insert into t1 values( 207 ) -master-bin.000001 17928 Query 1 18019 use `test`; insert into t1 values( 206 ) -master-bin.000001 18019 Query 1 18110 use `test`; insert into t1 values( 205 ) -master-bin.000001 18110 Query 1 18201 use `test`; insert into t1 values( 204 ) -master-bin.000001 18201 Query 1 18292 use `test`; insert into t1 values( 203 ) -master-bin.000001 18292 Query 1 18383 use `test`; insert into t1 values( 202 ) -master-bin.000001 18383 Query 1 18474 use `test`; insert into t1 values( 201 ) -master-bin.000001 18474 Query 1 18565 use `test`; insert into t1 values( 200 ) -master-bin.000001 18565 Query 1 18656 use `test`; insert into t1 values( 199 ) -master-bin.000001 18656 Query 1 18747 use `test`; insert into t1 values( 198 ) -master-bin.000001 18747 Query 1 18838 use `test`; insert into t1 values( 197 ) -master-bin.000001 18838 Query 1 18929 use `test`; insert into t1 values( 196 ) -master-bin.000001 18929 Query 1 19020 use `test`; insert into t1 values( 195 ) -master-bin.000001 19020 Query 1 19111 use `test`; insert into t1 values( 194 ) -master-bin.000001 19111 Query 1 19202 use `test`; insert into t1 values( 193 ) -master-bin.000001 19202 Query 1 19293 use `test`; insert into t1 values( 192 ) -master-bin.000001 19293 Query 1 19384 use `test`; insert into t1 values( 191 ) -master-bin.000001 19384 Query 1 19475 use `test`; insert into t1 values( 190 ) -master-bin.000001 19475 Query 1 19566 use `test`; insert into t1 values( 189 ) -master-bin.000001 19566 Query 1 19657 use `test`; insert into t1 values( 188 ) -master-bin.000001 19657 Query 1 19748 use `test`; insert into t1 values( 187 ) -master-bin.000001 19748 Query 1 19839 use `test`; insert into t1 values( 186 ) -master-bin.000001 19839 Query 1 19930 use `test`; insert into t1 values( 185 ) -master-bin.000001 19930 Query 1 20021 use `test`; insert into t1 values( 184 ) -master-bin.000001 20021 Query 1 20112 use `test`; insert into t1 values( 183 ) -master-bin.000001 20112 Query 1 20203 use `test`; insert into t1 values( 182 ) -master-bin.000001 20203 Query 1 20294 use `test`; insert into t1 values( 181 ) -master-bin.000001 20294 Query 1 20385 use `test`; insert into t1 values( 180 ) -master-bin.000001 20385 Query 1 20476 use `test`; insert into t1 values( 179 ) -master-bin.000001 20476 Query 1 20567 use `test`; insert into t1 values( 178 ) -master-bin.000001 20567 Query 1 20658 use `test`; insert into t1 values( 177 ) -master-bin.000001 20658 Query 1 20749 use `test`; insert into t1 values( 176 ) -master-bin.000001 20749 Query 1 20840 use `test`; insert into t1 values( 175 ) -master-bin.000001 20840 Query 1 20931 use `test`; insert into t1 values( 174 ) -master-bin.000001 20931 Query 1 21022 use `test`; insert into t1 values( 173 ) -master-bin.000001 21022 Query 1 21113 use `test`; insert into t1 values( 172 ) -master-bin.000001 21113 Query 1 21204 use `test`; insert into t1 values( 171 ) -master-bin.000001 21204 Query 1 21295 use `test`; insert into t1 values( 170 ) -master-bin.000001 21295 Query 1 21386 use `test`; insert into t1 values( 169 ) -master-bin.000001 21386 Query 1 21477 use `test`; insert into t1 values( 168 ) -master-bin.000001 21477 Query 1 21568 use `test`; insert into t1 values( 167 ) -master-bin.000001 21568 Query 1 21659 use `test`; insert into t1 values( 166 ) -master-bin.000001 21659 Query 1 21750 use `test`; insert into t1 values( 165 ) -master-bin.000001 21750 Query 1 21841 use `test`; insert into t1 values( 164 ) -master-bin.000001 21841 Query 1 21932 use `test`; insert into t1 values( 163 ) -master-bin.000001 21932 Query 1 22023 use `test`; insert into t1 values( 162 ) -master-bin.000001 22023 Query 1 22114 use `test`; insert into t1 values( 161 ) -master-bin.000001 22114 Query 1 22205 use `test`; insert into t1 values( 160 ) -master-bin.000001 22205 Query 1 22296 use `test`; insert into t1 values( 159 ) -master-bin.000001 22296 Query 1 22387 use `test`; insert into t1 values( 158 ) -master-bin.000001 22387 Query 1 22478 use `test`; insert into t1 values( 157 ) -master-bin.000001 22478 Query 1 22569 use `test`; insert into t1 values( 156 ) -master-bin.000001 22569 Query 1 22660 use `test`; insert into t1 values( 155 ) -master-bin.000001 22660 Query 1 22751 use `test`; insert into t1 values( 154 ) -master-bin.000001 22751 Query 1 22842 use `test`; insert into t1 values( 153 ) -master-bin.000001 22842 Query 1 22933 use `test`; insert into t1 values( 152 ) -master-bin.000001 22933 Query 1 23024 use `test`; insert into t1 values( 151 ) -master-bin.000001 23024 Query 1 23115 use `test`; insert into t1 values( 150 ) -master-bin.000001 23115 Query 1 23206 use `test`; insert into t1 values( 149 ) -master-bin.000001 23206 Query 1 23297 use `test`; insert into t1 values( 148 ) -master-bin.000001 23297 Query 1 23388 use `test`; insert into t1 values( 147 ) -master-bin.000001 23388 Query 1 23479 use `test`; insert into t1 values( 146 ) -master-bin.000001 23479 Query 1 23570 use `test`; insert into t1 values( 145 ) -master-bin.000001 23570 Query 1 23661 use `test`; insert into t1 values( 144 ) -master-bin.000001 23661 Query 1 23752 use `test`; insert into t1 values( 143 ) -master-bin.000001 23752 Query 1 23843 use `test`; insert into t1 values( 142 ) -master-bin.000001 23843 Query 1 23934 use `test`; insert into t1 values( 141 ) -master-bin.000001 23934 Query 1 24025 use `test`; insert into t1 values( 140 ) -master-bin.000001 24025 Query 1 24116 use `test`; insert into t1 values( 139 ) -master-bin.000001 24116 Query 1 24207 use `test`; insert into t1 values( 138 ) -master-bin.000001 24207 Query 1 24298 use `test`; insert into t1 values( 137 ) -master-bin.000001 24298 Query 1 24389 use `test`; insert into t1 values( 136 ) -master-bin.000001 24389 Query 1 24480 use `test`; insert into t1 values( 135 ) -master-bin.000001 24480 Query 1 24571 use `test`; insert into t1 values( 134 ) -master-bin.000001 24571 Query 1 24662 use `test`; insert into t1 values( 133 ) -master-bin.000001 24662 Query 1 24753 use `test`; insert into t1 values( 132 ) -master-bin.000001 24753 Query 1 24844 use `test`; insert into t1 values( 131 ) -master-bin.000001 24844 Query 1 24935 use `test`; insert into t1 values( 130 ) -master-bin.000001 24935 Query 1 25026 use `test`; insert into t1 values( 129 ) -master-bin.000001 25026 Query 1 25117 use `test`; insert into t1 values( 128 ) -master-bin.000001 25117 Query 1 25208 use `test`; insert into t1 values( 127 ) -master-bin.000001 25208 Query 1 25299 use `test`; insert into t1 values( 126 ) -master-bin.000001 25299 Query 1 25390 use `test`; insert into t1 values( 125 ) -master-bin.000001 25390 Query 1 25481 use `test`; insert into t1 values( 124 ) -master-bin.000001 25481 Query 1 25572 use `test`; insert into t1 values( 123 ) -master-bin.000001 25572 Query 1 25663 use `test`; insert into t1 values( 122 ) -master-bin.000001 25663 Query 1 25754 use `test`; insert into t1 values( 121 ) -master-bin.000001 25754 Query 1 25845 use `test`; insert into t1 values( 120 ) -master-bin.000001 25845 Query 1 25936 use `test`; insert into t1 values( 119 ) -master-bin.000001 25936 Query 1 26027 use `test`; insert into t1 values( 118 ) -master-bin.000001 26027 Query 1 26118 use `test`; insert into t1 values( 117 ) -master-bin.000001 26118 Query 1 26209 use `test`; insert into t1 values( 116 ) -master-bin.000001 26209 Query 1 26300 use `test`; insert into t1 values( 115 ) -master-bin.000001 26300 Query 1 26391 use `test`; insert into t1 values( 114 ) -master-bin.000001 26391 Query 1 26482 use `test`; insert into t1 values( 113 ) -master-bin.000001 26482 Query 1 26573 use `test`; insert into t1 values( 112 ) -master-bin.000001 26573 Query 1 26664 use `test`; insert into t1 values( 111 ) -master-bin.000001 26664 Query 1 26755 use `test`; insert into t1 values( 110 ) -master-bin.000001 26755 Query 1 26846 use `test`; insert into t1 values( 109 ) -master-bin.000001 26846 Query 1 26937 use `test`; insert into t1 values( 108 ) -master-bin.000001 26937 Query 1 27028 use `test`; insert into t1 values( 107 ) -master-bin.000001 27028 Query 1 27119 use `test`; insert into t1 values( 106 ) -master-bin.000001 27119 Query 1 27210 use `test`; insert into t1 values( 105 ) -master-bin.000001 27210 Query 1 27301 use `test`; insert into t1 values( 104 ) -master-bin.000001 27301 Query 1 27392 use `test`; insert into t1 values( 103 ) -master-bin.000001 27392 Query 1 27483 use `test`; insert into t1 values( 102 ) -master-bin.000001 27483 Query 1 27574 use `test`; insert into t1 values( 101 ) -master-bin.000001 27574 Query 1 27665 use `test`; insert into t1 values( 100 ) -master-bin.000001 27665 Query 1 27755 use `test`; insert into t1 values( 99 ) -master-bin.000001 27755 Query 1 27845 use `test`; insert into t1 values( 98 ) -master-bin.000001 27845 Query 1 27935 use `test`; insert into t1 values( 97 ) -master-bin.000001 27935 Query 1 28025 use `test`; insert into t1 values( 96 ) -master-bin.000001 28025 Query 1 28115 use `test`; insert into t1 values( 95 ) -master-bin.000001 28115 Query 1 28205 use `test`; insert into t1 values( 94 ) -master-bin.000001 28205 Query 1 28295 use `test`; insert into t1 values( 93 ) -master-bin.000001 28295 Query 1 28385 use `test`; insert into t1 values( 92 ) -master-bin.000001 28385 Query 1 28475 use `test`; insert into t1 values( 91 ) -master-bin.000001 28475 Query 1 28565 use `test`; insert into t1 values( 90 ) -master-bin.000001 28565 Query 1 28655 use `test`; insert into t1 values( 89 ) -master-bin.000001 28655 Query 1 28745 use `test`; insert into t1 values( 88 ) -master-bin.000001 28745 Query 1 28835 use `test`; insert into t1 values( 87 ) -master-bin.000001 28835 Query 1 28925 use `test`; insert into t1 values( 86 ) -master-bin.000001 28925 Query 1 29015 use `test`; insert into t1 values( 85 ) -master-bin.000001 29015 Query 1 29105 use `test`; insert into t1 values( 84 ) -master-bin.000001 29105 Query 1 29195 use `test`; insert into t1 values( 83 ) -master-bin.000001 29195 Query 1 29285 use `test`; insert into t1 values( 82 ) -master-bin.000001 29285 Query 1 29375 use `test`; insert into t1 values( 81 ) -master-bin.000001 29375 Query 1 29465 use `test`; insert into t1 values( 80 ) -master-bin.000001 29465 Query 1 29555 use `test`; insert into t1 values( 79 ) -master-bin.000001 29555 Query 1 29645 use `test`; insert into t1 values( 78 ) -master-bin.000001 29645 Query 1 29735 use `test`; insert into t1 values( 77 ) -master-bin.000001 29735 Query 1 29825 use `test`; insert into t1 values( 76 ) -master-bin.000001 29825 Query 1 29915 use `test`; insert into t1 values( 75 ) -master-bin.000001 29915 Query 1 30005 use `test`; insert into t1 values( 74 ) -master-bin.000001 30005 Query 1 30095 use `test`; insert into t1 values( 73 ) -master-bin.000001 30095 Query 1 30185 use `test`; insert into t1 values( 72 ) -master-bin.000001 30185 Query 1 30275 use `test`; insert into t1 values( 71 ) -master-bin.000001 30275 Query 1 30365 use `test`; insert into t1 values( 70 ) -master-bin.000001 30365 Query 1 30455 use `test`; insert into t1 values( 69 ) -master-bin.000001 30455 Query 1 30545 use `test`; insert into t1 values( 68 ) -master-bin.000001 30545 Query 1 30635 use `test`; insert into t1 values( 67 ) -master-bin.000001 30635 Query 1 30725 use `test`; insert into t1 values( 66 ) -master-bin.000001 30725 Query 1 30815 use `test`; insert into t1 values( 65 ) -master-bin.000001 30815 Query 1 30905 use `test`; insert into t1 values( 64 ) -master-bin.000001 30905 Query 1 30995 use `test`; insert into t1 values( 63 ) -master-bin.000001 30995 Query 1 31085 use `test`; insert into t1 values( 62 ) -master-bin.000001 31085 Query 1 31175 use `test`; insert into t1 values( 61 ) -master-bin.000001 31175 Query 1 31265 use `test`; insert into t1 values( 60 ) -master-bin.000001 31265 Query 1 31355 use `test`; insert into t1 values( 59 ) -master-bin.000001 31355 Query 1 31445 use `test`; insert into t1 values( 58 ) -master-bin.000001 31445 Query 1 31535 use `test`; insert into t1 values( 57 ) -master-bin.000001 31535 Query 1 31625 use `test`; insert into t1 values( 56 ) -master-bin.000001 31625 Query 1 31715 use `test`; insert into t1 values( 55 ) -master-bin.000001 31715 Query 1 31805 use `test`; insert into t1 values( 54 ) -master-bin.000001 31805 Query 1 31895 use `test`; insert into t1 values( 53 ) -master-bin.000001 31895 Query 1 31985 use `test`; insert into t1 values( 52 ) -master-bin.000001 31985 Query 1 32075 use `test`; insert into t1 values( 51 ) -master-bin.000001 32075 Query 1 32165 use `test`; insert into t1 values( 50 ) -master-bin.000001 32165 Query 1 32255 use `test`; insert into t1 values( 49 ) -master-bin.000001 32255 Query 1 32345 use `test`; insert into t1 values( 48 ) -master-bin.000001 32345 Query 1 32435 use `test`; insert into t1 values( 47 ) -master-bin.000001 32435 Query 1 32525 use `test`; insert into t1 values( 46 ) -master-bin.000001 32525 Query 1 32615 use `test`; insert into t1 values( 45 ) -master-bin.000001 32615 Query 1 32705 use `test`; insert into t1 values( 44 ) -master-bin.000001 32705 Query 1 32795 use `test`; insert into t1 values( 43 ) -master-bin.000001 32795 Query 1 32885 use `test`; insert into t1 values( 42 ) -master-bin.000001 32885 Query 1 32975 use `test`; insert into t1 values( 41 ) -master-bin.000001 32975 Query 1 33065 use `test`; insert into t1 values( 40 ) -master-bin.000001 33065 Query 1 33155 use `test`; insert into t1 values( 39 ) -master-bin.000001 33155 Query 1 33245 use `test`; insert into t1 values( 38 ) -master-bin.000001 33245 Query 1 33335 use `test`; insert into t1 values( 37 ) -master-bin.000001 33335 Query 1 33425 use `test`; insert into t1 values( 36 ) -master-bin.000001 33425 Query 1 33515 use `test`; insert into t1 values( 35 ) -master-bin.000001 33515 Query 1 33605 use `test`; insert into t1 values( 34 ) -master-bin.000001 33605 Query 1 33695 use `test`; insert into t1 values( 33 ) -master-bin.000001 33695 Query 1 33785 use `test`; insert into t1 values( 32 ) -master-bin.000001 33785 Query 1 33875 use `test`; insert into t1 values( 31 ) -master-bin.000001 33875 Query 1 33965 use `test`; insert into t1 values( 30 ) -master-bin.000001 33965 Query 1 34055 use `test`; insert into t1 values( 29 ) -master-bin.000001 34055 Query 1 34145 use `test`; insert into t1 values( 28 ) -master-bin.000001 34145 Query 1 34235 use `test`; insert into t1 values( 27 ) -master-bin.000001 34235 Query 1 34325 use `test`; insert into t1 values( 26 ) -master-bin.000001 34325 Query 1 34415 use `test`; insert into t1 values( 25 ) -master-bin.000001 34415 Query 1 34505 use `test`; insert into t1 values( 24 ) -master-bin.000001 34505 Query 1 34595 use `test`; insert into t1 values( 23 ) -master-bin.000001 34595 Query 1 34685 use `test`; insert into t1 values( 22 ) -master-bin.000001 34685 Query 1 34775 use `test`; insert into t1 values( 21 ) -master-bin.000001 34775 Query 1 34865 use `test`; insert into t1 values( 20 ) -master-bin.000001 34865 Query 1 34955 use `test`; insert into t1 values( 19 ) -master-bin.000001 34955 Query 1 35045 use `test`; insert into t1 values( 18 ) -master-bin.000001 35045 Query 1 35135 use `test`; insert into t1 values( 17 ) -master-bin.000001 35135 Query 1 35225 use `test`; insert into t1 values( 16 ) -master-bin.000001 35225 Query 1 35315 use `test`; insert into t1 values( 15 ) -master-bin.000001 35315 Query 1 35405 use `test`; insert into t1 values( 14 ) -master-bin.000001 35405 Query 1 35495 use `test`; insert into t1 values( 13 ) -master-bin.000001 35495 Query 1 35585 use `test`; insert into t1 values( 12 ) -master-bin.000001 35585 Query 1 35675 use `test`; insert into t1 values( 11 ) -master-bin.000001 35675 Query 1 35765 use `test`; insert into t1 values( 10 ) -master-bin.000001 35765 Query 1 35854 use `test`; insert into t1 values( 9 ) -master-bin.000001 35854 Query 1 35943 use `test`; insert into t1 values( 8 ) -master-bin.000001 35943 Query 1 36032 use `test`; insert into t1 values( 7 ) -master-bin.000001 36032 Query 1 36121 use `test`; insert into t1 values( 6 ) -master-bin.000001 36121 Query 1 36210 use `test`; insert into t1 values( 5 ) -master-bin.000001 36210 Query 1 36299 use `test`; insert into t1 values( 4 ) -master-bin.000001 36299 Query 1 36388 use `test`; insert into t1 values( 3 ) -master-bin.000001 36388 Query 1 36477 use `test`; insert into t1 values( 2 ) -master-bin.000001 36477 Query 1 36566 use `test`; insert into t1 values( 1 ) -master-bin.000001 36566 Xid 1 36593 COMMIT /* XID */ -master-bin.000001 36593 Rotate 1 36637 master-bin.000002;pos=4 +master-bin.000001 4 Format_desc 1 107 Server version, Binlog ver: 4 +master-bin.000001 107 Query 1 207 use `test`; create table t1 (a int) engine=innodb +master-bin.000001 207 Query 1 275 BEGIN +master-bin.000001 275 Query 1 366 use `test`; insert into t1 values( 400 ) +master-bin.000001 366 Query 1 457 use `test`; insert into t1 values( 399 ) +master-bin.000001 457 Query 1 548 use `test`; insert into t1 values( 398 ) +master-bin.000001 548 Query 1 639 use `test`; insert into t1 values( 397 ) +master-bin.000001 639 Query 1 730 use `test`; insert into t1 values( 396 ) +master-bin.000001 730 Query 1 821 use `test`; insert into t1 values( 395 ) +master-bin.000001 821 Query 1 912 use `test`; insert into t1 values( 394 ) +master-bin.000001 912 Query 1 1003 use `test`; insert into t1 values( 393 ) +master-bin.000001 1003 Query 1 1094 use `test`; insert into t1 values( 392 ) +master-bin.000001 1094 Query 1 1185 use `test`; insert into t1 values( 391 ) +master-bin.000001 1185 Query 1 1276 use `test`; insert into t1 values( 390 ) +master-bin.000001 1276 Query 1 1367 use `test`; insert into t1 values( 389 ) +master-bin.000001 1367 Query 1 1458 use `test`; insert into t1 values( 388 ) +master-bin.000001 1458 Query 1 1549 use `test`; insert into t1 values( 387 ) +master-bin.000001 1549 Query 1 1640 use `test`; insert into t1 values( 386 ) +master-bin.000001 1640 Query 1 1731 use `test`; insert into t1 values( 385 ) +master-bin.000001 1731 Query 1 1822 use `test`; insert into t1 values( 384 ) +master-bin.000001 1822 Query 1 1913 use `test`; insert into t1 values( 383 ) +master-bin.000001 1913 Query 1 2004 use `test`; insert into t1 values( 382 ) +master-bin.000001 2004 Query 1 2095 use `test`; insert into t1 values( 381 ) +master-bin.000001 2095 Query 1 2186 use `test`; insert into t1 values( 380 ) +master-bin.000001 2186 Query 1 2277 use `test`; insert into t1 values( 379 ) +master-bin.000001 2277 Query 1 2368 use `test`; insert into t1 values( 378 ) +master-bin.000001 2368 Query 1 2459 use `test`; insert into t1 values( 377 ) +master-bin.000001 2459 Query 1 2550 use `test`; insert into t1 values( 376 ) +master-bin.000001 2550 Query 1 2641 use `test`; insert into t1 values( 375 ) +master-bin.000001 2641 Query 1 2732 use `test`; insert into t1 values( 374 ) +master-bin.000001 2732 Query 1 2823 use `test`; insert into t1 values( 373 ) +master-bin.000001 2823 Query 1 2914 use `test`; insert into t1 values( 372 ) +master-bin.000001 2914 Query 1 3005 use `test`; insert into t1 values( 371 ) +master-bin.000001 3005 Query 1 3096 use `test`; insert into t1 values( 370 ) +master-bin.000001 3096 Query 1 3187 use `test`; insert into t1 values( 369 ) +master-bin.000001 3187 Query 1 3278 use `test`; insert into t1 values( 368 ) +master-bin.000001 3278 Query 1 3369 use `test`; insert into t1 values( 367 ) +master-bin.000001 3369 Query 1 3460 use `test`; insert into t1 values( 366 ) +master-bin.000001 3460 Query 1 3551 use `test`; insert into t1 values( 365 ) +master-bin.000001 3551 Query 1 3642 use `test`; insert into t1 values( 364 ) +master-bin.000001 3642 Query 1 3733 use `test`; insert into t1 values( 363 ) +master-bin.000001 3733 Query 1 3824 use `test`; insert into t1 values( 362 ) +master-bin.000001 3824 Query 1 3915 use `test`; insert into t1 values( 361 ) +master-bin.000001 3915 Query 1 4006 use `test`; insert into t1 values( 360 ) +master-bin.000001 4006 Query 1 4097 use `test`; insert into t1 values( 359 ) +master-bin.000001 4097 Query 1 4188 use `test`; insert into t1 values( 358 ) +master-bin.000001 4188 Query 1 4279 use `test`; insert into t1 values( 357 ) +master-bin.000001 4279 Query 1 4370 use `test`; insert into t1 values( 356 ) +master-bin.000001 4370 Query 1 4461 use `test`; insert into t1 values( 355 ) +master-bin.000001 4461 Query 1 4552 use `test`; insert into t1 values( 354 ) +master-bin.000001 4552 Query 1 4643 use `test`; insert into t1 values( 353 ) +master-bin.000001 4643 Query 1 4734 use `test`; insert into t1 values( 352 ) +master-bin.000001 4734 Query 1 4825 use `test`; insert into t1 values( 351 ) +master-bin.000001 4825 Query 1 4916 use `test`; insert into t1 values( 350 ) +master-bin.000001 4916 Query 1 5007 use `test`; insert into t1 values( 349 ) +master-bin.000001 5007 Query 1 5098 use `test`; insert into t1 values( 348 ) +master-bin.000001 5098 Query 1 5189 use `test`; insert into t1 values( 347 ) +master-bin.000001 5189 Query 1 5280 use `test`; insert into t1 values( 346 ) +master-bin.000001 5280 Query 1 5371 use `test`; insert into t1 values( 345 ) +master-bin.000001 5371 Query 1 5462 use `test`; insert into t1 values( 344 ) +master-bin.000001 5462 Query 1 5553 use `test`; insert into t1 values( 343 ) +master-bin.000001 5553 Query 1 5644 use `test`; insert into t1 values( 342 ) +master-bin.000001 5644 Query 1 5735 use `test`; insert into t1 values( 341 ) +master-bin.000001 5735 Query 1 5826 use `test`; insert into t1 values( 340 ) +master-bin.000001 5826 Query 1 5917 use `test`; insert into t1 values( 339 ) +master-bin.000001 5917 Query 1 6008 use `test`; insert into t1 values( 338 ) +master-bin.000001 6008 Query 1 6099 use `test`; insert into t1 values( 337 ) +master-bin.000001 6099 Query 1 6190 use `test`; insert into t1 values( 336 ) +master-bin.000001 6190 Query 1 6281 use `test`; insert into t1 values( 335 ) +master-bin.000001 6281 Query 1 6372 use `test`; insert into t1 values( 334 ) +master-bin.000001 6372 Query 1 6463 use `test`; insert into t1 values( 333 ) +master-bin.000001 6463 Query 1 6554 use `test`; insert into t1 values( 332 ) +master-bin.000001 6554 Query 1 6645 use `test`; insert into t1 values( 331 ) +master-bin.000001 6645 Query 1 6736 use `test`; insert into t1 values( 330 ) +master-bin.000001 6736 Query 1 6827 use `test`; insert into t1 values( 329 ) +master-bin.000001 6827 Query 1 6918 use `test`; insert into t1 values( 328 ) +master-bin.000001 6918 Query 1 7009 use `test`; insert into t1 values( 327 ) +master-bin.000001 7009 Query 1 7100 use `test`; insert into t1 values( 326 ) +master-bin.000001 7100 Query 1 7191 use `test`; insert into t1 values( 325 ) +master-bin.000001 7191 Query 1 7282 use `test`; insert into t1 values( 324 ) +master-bin.000001 7282 Query 1 7373 use `test`; insert into t1 values( 323 ) +master-bin.000001 7373 Query 1 7464 use `test`; insert into t1 values( 322 ) +master-bin.000001 7464 Query 1 7555 use `test`; insert into t1 values( 321 ) +master-bin.000001 7555 Query 1 7646 use `test`; insert into t1 values( 320 ) +master-bin.000001 7646 Query 1 7737 use `test`; insert into t1 values( 319 ) +master-bin.000001 7737 Query 1 7828 use `test`; insert into t1 values( 318 ) +master-bin.000001 7828 Query 1 7919 use `test`; insert into t1 values( 317 ) +master-bin.000001 7919 Query 1 8010 use `test`; insert into t1 values( 316 ) +master-bin.000001 8010 Query 1 8101 use `test`; insert into t1 values( 315 ) +master-bin.000001 8101 Query 1 8192 use `test`; insert into t1 values( 314 ) +master-bin.000001 8192 Query 1 8283 use `test`; insert into t1 values( 313 ) +master-bin.000001 8283 Query 1 8374 use `test`; insert into t1 values( 312 ) +master-bin.000001 8374 Query 1 8465 use `test`; insert into t1 values( 311 ) +master-bin.000001 8465 Query 1 8556 use `test`; insert into t1 values( 310 ) +master-bin.000001 8556 Query 1 8647 use `test`; insert into t1 values( 309 ) +master-bin.000001 8647 Query 1 8738 use `test`; insert into t1 values( 308 ) +master-bin.000001 8738 Query 1 8829 use `test`; insert into t1 values( 307 ) +master-bin.000001 8829 Query 1 8920 use `test`; insert into t1 values( 306 ) +master-bin.000001 8920 Query 1 9011 use `test`; insert into t1 values( 305 ) +master-bin.000001 9011 Query 1 9102 use `test`; insert into t1 values( 304 ) +master-bin.000001 9102 Query 1 9193 use `test`; insert into t1 values( 303 ) +master-bin.000001 9193 Query 1 9284 use `test`; insert into t1 values( 302 ) +master-bin.000001 9284 Query 1 9375 use `test`; insert into t1 values( 301 ) +master-bin.000001 9375 Query 1 9466 use `test`; insert into t1 values( 300 ) +master-bin.000001 9466 Query 1 9557 use `test`; insert into t1 values( 299 ) +master-bin.000001 9557 Query 1 9648 use `test`; insert into t1 values( 298 ) +master-bin.000001 9648 Query 1 9739 use `test`; insert into t1 values( 297 ) +master-bin.000001 9739 Query 1 9830 use `test`; insert into t1 values( 296 ) +master-bin.000001 9830 Query 1 9921 use `test`; insert into t1 values( 295 ) +master-bin.000001 9921 Query 1 10012 use `test`; insert into t1 values( 294 ) +master-bin.000001 10012 Query 1 10103 use `test`; insert into t1 values( 293 ) +master-bin.000001 10103 Query 1 10194 use `test`; insert into t1 values( 292 ) +master-bin.000001 10194 Query 1 10285 use `test`; insert into t1 values( 291 ) +master-bin.000001 10285 Query 1 10376 use `test`; insert into t1 values( 290 ) +master-bin.000001 10376 Query 1 10467 use `test`; insert into t1 values( 289 ) +master-bin.000001 10467 Query 1 10558 use `test`; insert into t1 values( 288 ) +master-bin.000001 10558 Query 1 10649 use `test`; insert into t1 values( 287 ) +master-bin.000001 10649 Query 1 10740 use `test`; insert into t1 values( 286 ) +master-bin.000001 10740 Query 1 10831 use `test`; insert into t1 values( 285 ) +master-bin.000001 10831 Query 1 10922 use `test`; insert into t1 values( 284 ) +master-bin.000001 10922 Query 1 11013 use `test`; insert into t1 values( 283 ) +master-bin.000001 11013 Query 1 11104 use `test`; insert into t1 values( 282 ) +master-bin.000001 11104 Query 1 11195 use `test`; insert into t1 values( 281 ) +master-bin.000001 11195 Query 1 11286 use `test`; insert into t1 values( 280 ) +master-bin.000001 11286 Query 1 11377 use `test`; insert into t1 values( 279 ) +master-bin.000001 11377 Query 1 11468 use `test`; insert into t1 values( 278 ) +master-bin.000001 11468 Query 1 11559 use `test`; insert into t1 values( 277 ) +master-bin.000001 11559 Query 1 11650 use `test`; insert into t1 values( 276 ) +master-bin.000001 11650 Query 1 11741 use `test`; insert into t1 values( 275 ) +master-bin.000001 11741 Query 1 11832 use `test`; insert into t1 values( 274 ) +master-bin.000001 11832 Query 1 11923 use `test`; insert into t1 values( 273 ) +master-bin.000001 11923 Query 1 12014 use `test`; insert into t1 values( 272 ) +master-bin.000001 12014 Query 1 12105 use `test`; insert into t1 values( 271 ) +master-bin.000001 12105 Query 1 12196 use `test`; insert into t1 values( 270 ) +master-bin.000001 12196 Query 1 12287 use `test`; insert into t1 values( 269 ) +master-bin.000001 12287 Query 1 12378 use `test`; insert into t1 values( 268 ) +master-bin.000001 12378 Query 1 12469 use `test`; insert into t1 values( 267 ) +master-bin.000001 12469 Query 1 12560 use `test`; insert into t1 values( 266 ) +master-bin.000001 12560 Query 1 12651 use `test`; insert into t1 values( 265 ) +master-bin.000001 12651 Query 1 12742 use `test`; insert into t1 values( 264 ) +master-bin.000001 12742 Query 1 12833 use `test`; insert into t1 values( 263 ) +master-bin.000001 12833 Query 1 12924 use `test`; insert into t1 values( 262 ) +master-bin.000001 12924 Query 1 13015 use `test`; insert into t1 values( 261 ) +master-bin.000001 13015 Query 1 13106 use `test`; insert into t1 values( 260 ) +master-bin.000001 13106 Query 1 13197 use `test`; insert into t1 values( 259 ) +master-bin.000001 13197 Query 1 13288 use `test`; insert into t1 values( 258 ) +master-bin.000001 13288 Query 1 13379 use `test`; insert into t1 values( 257 ) +master-bin.000001 13379 Query 1 13470 use `test`; insert into t1 values( 256 ) +master-bin.000001 13470 Query 1 13561 use `test`; insert into t1 values( 255 ) +master-bin.000001 13561 Query 1 13652 use `test`; insert into t1 values( 254 ) +master-bin.000001 13652 Query 1 13743 use `test`; insert into t1 values( 253 ) +master-bin.000001 13743 Query 1 13834 use `test`; insert into t1 values( 252 ) +master-bin.000001 13834 Query 1 13925 use `test`; insert into t1 values( 251 ) +master-bin.000001 13925 Query 1 14016 use `test`; insert into t1 values( 250 ) +master-bin.000001 14016 Query 1 14107 use `test`; insert into t1 values( 249 ) +master-bin.000001 14107 Query 1 14198 use `test`; insert into t1 values( 248 ) +master-bin.000001 14198 Query 1 14289 use `test`; insert into t1 values( 247 ) +master-bin.000001 14289 Query 1 14380 use `test`; insert into t1 values( 246 ) +master-bin.000001 14380 Query 1 14471 use `test`; insert into t1 values( 245 ) +master-bin.000001 14471 Query 1 14562 use `test`; insert into t1 values( 244 ) +master-bin.000001 14562 Query 1 14653 use `test`; insert into t1 values( 243 ) +master-bin.000001 14653 Query 1 14744 use `test`; insert into t1 values( 242 ) +master-bin.000001 14744 Query 1 14835 use `test`; insert into t1 values( 241 ) +master-bin.000001 14835 Query 1 14926 use `test`; insert into t1 values( 240 ) +master-bin.000001 14926 Query 1 15017 use `test`; insert into t1 values( 239 ) +master-bin.000001 15017 Query 1 15108 use `test`; insert into t1 values( 238 ) +master-bin.000001 15108 Query 1 15199 use `test`; insert into t1 values( 237 ) +master-bin.000001 15199 Query 1 15290 use `test`; insert into t1 values( 236 ) +master-bin.000001 15290 Query 1 15381 use `test`; insert into t1 values( 235 ) +master-bin.000001 15381 Query 1 15472 use `test`; insert into t1 values( 234 ) +master-bin.000001 15472 Query 1 15563 use `test`; insert into t1 values( 233 ) +master-bin.000001 15563 Query 1 15654 use `test`; insert into t1 values( 232 ) +master-bin.000001 15654 Query 1 15745 use `test`; insert into t1 values( 231 ) +master-bin.000001 15745 Query 1 15836 use `test`; insert into t1 values( 230 ) +master-bin.000001 15836 Query 1 15927 use `test`; insert into t1 values( 229 ) +master-bin.000001 15927 Query 1 16018 use `test`; insert into t1 values( 228 ) +master-bin.000001 16018 Query 1 16109 use `test`; insert into t1 values( 227 ) +master-bin.000001 16109 Query 1 16200 use `test`; insert into t1 values( 226 ) +master-bin.000001 16200 Query 1 16291 use `test`; insert into t1 values( 225 ) +master-bin.000001 16291 Query 1 16382 use `test`; insert into t1 values( 224 ) +master-bin.000001 16382 Query 1 16473 use `test`; insert into t1 values( 223 ) +master-bin.000001 16473 Query 1 16564 use `test`; insert into t1 values( 222 ) +master-bin.000001 16564 Query 1 16655 use `test`; insert into t1 values( 221 ) +master-bin.000001 16655 Query 1 16746 use `test`; insert into t1 values( 220 ) +master-bin.000001 16746 Query 1 16837 use `test`; insert into t1 values( 219 ) +master-bin.000001 16837 Query 1 16928 use `test`; insert into t1 values( 218 ) +master-bin.000001 16928 Query 1 17019 use `test`; insert into t1 values( 217 ) +master-bin.000001 17019 Query 1 17110 use `test`; insert into t1 values( 216 ) +master-bin.000001 17110 Query 1 17201 use `test`; insert into t1 values( 215 ) +master-bin.000001 17201 Query 1 17292 use `test`; insert into t1 values( 214 ) +master-bin.000001 17292 Query 1 17383 use `test`; insert into t1 values( 213 ) +master-bin.000001 17383 Query 1 17474 use `test`; insert into t1 values( 212 ) +master-bin.000001 17474 Query 1 17565 use `test`; insert into t1 values( 211 ) +master-bin.000001 17565 Query 1 17656 use `test`; insert into t1 values( 210 ) +master-bin.000001 17656 Query 1 17747 use `test`; insert into t1 values( 209 ) +master-bin.000001 17747 Query 1 17838 use `test`; insert into t1 values( 208 ) +master-bin.000001 17838 Query 1 17929 use `test`; insert into t1 values( 207 ) +master-bin.000001 17929 Query 1 18020 use `test`; insert into t1 values( 206 ) +master-bin.000001 18020 Query 1 18111 use `test`; insert into t1 values( 205 ) +master-bin.000001 18111 Query 1 18202 use `test`; insert into t1 values( 204 ) +master-bin.000001 18202 Query 1 18293 use `test`; insert into t1 values( 203 ) +master-bin.000001 18293 Query 1 18384 use `test`; insert into t1 values( 202 ) +master-bin.000001 18384 Query 1 18475 use `test`; insert into t1 values( 201 ) +master-bin.000001 18475 Query 1 18566 use `test`; insert into t1 values( 200 ) +master-bin.000001 18566 Query 1 18657 use `test`; insert into t1 values( 199 ) +master-bin.000001 18657 Query 1 18748 use `test`; insert into t1 values( 198 ) +master-bin.000001 18748 Query 1 18839 use `test`; insert into t1 values( 197 ) +master-bin.000001 18839 Query 1 18930 use `test`; insert into t1 values( 196 ) +master-bin.000001 18930 Query 1 19021 use `test`; insert into t1 values( 195 ) +master-bin.000001 19021 Query 1 19112 use `test`; insert into t1 values( 194 ) +master-bin.000001 19112 Query 1 19203 use `test`; insert into t1 values( 193 ) +master-bin.000001 19203 Query 1 19294 use `test`; insert into t1 values( 192 ) +master-bin.000001 19294 Query 1 19385 use `test`; insert into t1 values( 191 ) +master-bin.000001 19385 Query 1 19476 use `test`; insert into t1 values( 190 ) +master-bin.000001 19476 Query 1 19567 use `test`; insert into t1 values( 189 ) +master-bin.000001 19567 Query 1 19658 use `test`; insert into t1 values( 188 ) +master-bin.000001 19658 Query 1 19749 use `test`; insert into t1 values( 187 ) +master-bin.000001 19749 Query 1 19840 use `test`; insert into t1 values( 186 ) +master-bin.000001 19840 Query 1 19931 use `test`; insert into t1 values( 185 ) +master-bin.000001 19931 Query 1 20022 use `test`; insert into t1 values( 184 ) +master-bin.000001 20022 Query 1 20113 use `test`; insert into t1 values( 183 ) +master-bin.000001 20113 Query 1 20204 use `test`; insert into t1 values( 182 ) +master-bin.000001 20204 Query 1 20295 use `test`; insert into t1 values( 181 ) +master-bin.000001 20295 Query 1 20386 use `test`; insert into t1 values( 180 ) +master-bin.000001 20386 Query 1 20477 use `test`; insert into t1 values( 179 ) +master-bin.000001 20477 Query 1 20568 use `test`; insert into t1 values( 178 ) +master-bin.000001 20568 Query 1 20659 use `test`; insert into t1 values( 177 ) +master-bin.000001 20659 Query 1 20750 use `test`; insert into t1 values( 176 ) +master-bin.000001 20750 Query 1 20841 use `test`; insert into t1 values( 175 ) +master-bin.000001 20841 Query 1 20932 use `test`; insert into t1 values( 174 ) +master-bin.000001 20932 Query 1 21023 use `test`; insert into t1 values( 173 ) +master-bin.000001 21023 Query 1 21114 use `test`; insert into t1 values( 172 ) +master-bin.000001 21114 Query 1 21205 use `test`; insert into t1 values( 171 ) +master-bin.000001 21205 Query 1 21296 use `test`; insert into t1 values( 170 ) +master-bin.000001 21296 Query 1 21387 use `test`; insert into t1 values( 169 ) +master-bin.000001 21387 Query 1 21478 use `test`; insert into t1 values( 168 ) +master-bin.000001 21478 Query 1 21569 use `test`; insert into t1 values( 167 ) +master-bin.000001 21569 Query 1 21660 use `test`; insert into t1 values( 166 ) +master-bin.000001 21660 Query 1 21751 use `test`; insert into t1 values( 165 ) +master-bin.000001 21751 Query 1 21842 use `test`; insert into t1 values( 164 ) +master-bin.000001 21842 Query 1 21933 use `test`; insert into t1 values( 163 ) +master-bin.000001 21933 Query 1 22024 use `test`; insert into t1 values( 162 ) +master-bin.000001 22024 Query 1 22115 use `test`; insert into t1 values( 161 ) +master-bin.000001 22115 Query 1 22206 use `test`; insert into t1 values( 160 ) +master-bin.000001 22206 Query 1 22297 use `test`; insert into t1 values( 159 ) +master-bin.000001 22297 Query 1 22388 use `test`; insert into t1 values( 158 ) +master-bin.000001 22388 Query 1 22479 use `test`; insert into t1 values( 157 ) +master-bin.000001 22479 Query 1 22570 use `test`; insert into t1 values( 156 ) +master-bin.000001 22570 Query 1 22661 use `test`; insert into t1 values( 155 ) +master-bin.000001 22661 Query 1 22752 use `test`; insert into t1 values( 154 ) +master-bin.000001 22752 Query 1 22843 use `test`; insert into t1 values( 153 ) +master-bin.000001 22843 Query 1 22934 use `test`; insert into t1 values( 152 ) +master-bin.000001 22934 Query 1 23025 use `test`; insert into t1 values( 151 ) +master-bin.000001 23025 Query 1 23116 use `test`; insert into t1 values( 150 ) +master-bin.000001 23116 Query 1 23207 use `test`; insert into t1 values( 149 ) +master-bin.000001 23207 Query 1 23298 use `test`; insert into t1 values( 148 ) +master-bin.000001 23298 Query 1 23389 use `test`; insert into t1 values( 147 ) +master-bin.000001 23389 Query 1 23480 use `test`; insert into t1 values( 146 ) +master-bin.000001 23480 Query 1 23571 use `test`; insert into t1 values( 145 ) +master-bin.000001 23571 Query 1 23662 use `test`; insert into t1 values( 144 ) +master-bin.000001 23662 Query 1 23753 use `test`; insert into t1 values( 143 ) +master-bin.000001 23753 Query 1 23844 use `test`; insert into t1 values( 142 ) +master-bin.000001 23844 Query 1 23935 use `test`; insert into t1 values( 141 ) +master-bin.000001 23935 Query 1 24026 use `test`; insert into t1 values( 140 ) +master-bin.000001 24026 Query 1 24117 use `test`; insert into t1 values( 139 ) +master-bin.000001 24117 Query 1 24208 use `test`; insert into t1 values( 138 ) +master-bin.000001 24208 Query 1 24299 use `test`; insert into t1 values( 137 ) +master-bin.000001 24299 Query 1 24390 use `test`; insert into t1 values( 136 ) +master-bin.000001 24390 Query 1 24481 use `test`; insert into t1 values( 135 ) +master-bin.000001 24481 Query 1 24572 use `test`; insert into t1 values( 134 ) +master-bin.000001 24572 Query 1 24663 use `test`; insert into t1 values( 133 ) +master-bin.000001 24663 Query 1 24754 use `test`; insert into t1 values( 132 ) +master-bin.000001 24754 Query 1 24845 use `test`; insert into t1 values( 131 ) +master-bin.000001 24845 Query 1 24936 use `test`; insert into t1 values( 130 ) +master-bin.000001 24936 Query 1 25027 use `test`; insert into t1 values( 129 ) +master-bin.000001 25027 Query 1 25118 use `test`; insert into t1 values( 128 ) +master-bin.000001 25118 Query 1 25209 use `test`; insert into t1 values( 127 ) +master-bin.000001 25209 Query 1 25300 use `test`; insert into t1 values( 126 ) +master-bin.000001 25300 Query 1 25391 use `test`; insert into t1 values( 125 ) +master-bin.000001 25391 Query 1 25482 use `test`; insert into t1 values( 124 ) +master-bin.000001 25482 Query 1 25573 use `test`; insert into t1 values( 123 ) +master-bin.000001 25573 Query 1 25664 use `test`; insert into t1 values( 122 ) +master-bin.000001 25664 Query 1 25755 use `test`; insert into t1 values( 121 ) +master-bin.000001 25755 Query 1 25846 use `test`; insert into t1 values( 120 ) +master-bin.000001 25846 Query 1 25937 use `test`; insert into t1 values( 119 ) +master-bin.000001 25937 Query 1 26028 use `test`; insert into t1 values( 118 ) +master-bin.000001 26028 Query 1 26119 use `test`; insert into t1 values( 117 ) +master-bin.000001 26119 Query 1 26210 use `test`; insert into t1 values( 116 ) +master-bin.000001 26210 Query 1 26301 use `test`; insert into t1 values( 115 ) +master-bin.000001 26301 Query 1 26392 use `test`; insert into t1 values( 114 ) +master-bin.000001 26392 Query 1 26483 use `test`; insert into t1 values( 113 ) +master-bin.000001 26483 Query 1 26574 use `test`; insert into t1 values( 112 ) +master-bin.000001 26574 Query 1 26665 use `test`; insert into t1 values( 111 ) +master-bin.000001 26665 Query 1 26756 use `test`; insert into t1 values( 110 ) +master-bin.000001 26756 Query 1 26847 use `test`; insert into t1 values( 109 ) +master-bin.000001 26847 Query 1 26938 use `test`; insert into t1 values( 108 ) +master-bin.000001 26938 Query 1 27029 use `test`; insert into t1 values( 107 ) +master-bin.000001 27029 Query 1 27120 use `test`; insert into t1 values( 106 ) +master-bin.000001 27120 Query 1 27211 use `test`; insert into t1 values( 105 ) +master-bin.000001 27211 Query 1 27302 use `test`; insert into t1 values( 104 ) +master-bin.000001 27302 Query 1 27393 use `test`; insert into t1 values( 103 ) +master-bin.000001 27393 Query 1 27484 use `test`; insert into t1 values( 102 ) +master-bin.000001 27484 Query 1 27575 use `test`; insert into t1 values( 101 ) +master-bin.000001 27575 Query 1 27666 use `test`; insert into t1 values( 100 ) +master-bin.000001 27666 Query 1 27756 use `test`; insert into t1 values( 99 ) +master-bin.000001 27756 Query 1 27846 use `test`; insert into t1 values( 98 ) +master-bin.000001 27846 Query 1 27936 use `test`; insert into t1 values( 97 ) +master-bin.000001 27936 Query 1 28026 use `test`; insert into t1 values( 96 ) +master-bin.000001 28026 Query 1 28116 use `test`; insert into t1 values( 95 ) +master-bin.000001 28116 Query 1 28206 use `test`; insert into t1 values( 94 ) +master-bin.000001 28206 Query 1 28296 use `test`; insert into t1 values( 93 ) +master-bin.000001 28296 Query 1 28386 use `test`; insert into t1 values( 92 ) +master-bin.000001 28386 Query 1 28476 use `test`; insert into t1 values( 91 ) +master-bin.000001 28476 Query 1 28566 use `test`; insert into t1 values( 90 ) +master-bin.000001 28566 Query 1 28656 use `test`; insert into t1 values( 89 ) +master-bin.000001 28656 Query 1 28746 use `test`; insert into t1 values( 88 ) +master-bin.000001 28746 Query 1 28836 use `test`; insert into t1 values( 87 ) +master-bin.000001 28836 Query 1 28926 use `test`; insert into t1 values( 86 ) +master-bin.000001 28926 Query 1 29016 use `test`; insert into t1 values( 85 ) +master-bin.000001 29016 Query 1 29106 use `test`; insert into t1 values( 84 ) +master-bin.000001 29106 Query 1 29196 use `test`; insert into t1 values( 83 ) +master-bin.000001 29196 Query 1 29286 use `test`; insert into t1 values( 82 ) +master-bin.000001 29286 Query 1 29376 use `test`; insert into t1 values( 81 ) +master-bin.000001 29376 Query 1 29466 use `test`; insert into t1 values( 80 ) +master-bin.000001 29466 Query 1 29556 use `test`; insert into t1 values( 79 ) +master-bin.000001 29556 Query 1 29646 use `test`; insert into t1 values( 78 ) +master-bin.000001 29646 Query 1 29736 use `test`; insert into t1 values( 77 ) +master-bin.000001 29736 Query 1 29826 use `test`; insert into t1 values( 76 ) +master-bin.000001 29826 Query 1 29916 use `test`; insert into t1 values( 75 ) +master-bin.000001 29916 Query 1 30006 use `test`; insert into t1 values( 74 ) +master-bin.000001 30006 Query 1 30096 use `test`; insert into t1 values( 73 ) +master-bin.000001 30096 Query 1 30186 use `test`; insert into t1 values( 72 ) +master-bin.000001 30186 Query 1 30276 use `test`; insert into t1 values( 71 ) +master-bin.000001 30276 Query 1 30366 use `test`; insert into t1 values( 70 ) +master-bin.000001 30366 Query 1 30456 use `test`; insert into t1 values( 69 ) +master-bin.000001 30456 Query 1 30546 use `test`; insert into t1 values( 68 ) +master-bin.000001 30546 Query 1 30636 use `test`; insert into t1 values( 67 ) +master-bin.000001 30636 Query 1 30726 use `test`; insert into t1 values( 66 ) +master-bin.000001 30726 Query 1 30816 use `test`; insert into t1 values( 65 ) +master-bin.000001 30816 Query 1 30906 use `test`; insert into t1 values( 64 ) +master-bin.000001 30906 Query 1 30996 use `test`; insert into t1 values( 63 ) +master-bin.000001 30996 Query 1 31086 use `test`; insert into t1 values( 62 ) +master-bin.000001 31086 Query 1 31176 use `test`; insert into t1 values( 61 ) +master-bin.000001 31176 Query 1 31266 use `test`; insert into t1 values( 60 ) +master-bin.000001 31266 Query 1 31356 use `test`; insert into t1 values( 59 ) +master-bin.000001 31356 Query 1 31446 use `test`; insert into t1 values( 58 ) +master-bin.000001 31446 Query 1 31536 use `test`; insert into t1 values( 57 ) +master-bin.000001 31536 Query 1 31626 use `test`; insert into t1 values( 56 ) +master-bin.000001 31626 Query 1 31716 use `test`; insert into t1 values( 55 ) +master-bin.000001 31716 Query 1 31806 use `test`; insert into t1 values( 54 ) +master-bin.000001 31806 Query 1 31896 use `test`; insert into t1 values( 53 ) +master-bin.000001 31896 Query 1 31986 use `test`; insert into t1 values( 52 ) +master-bin.000001 31986 Query 1 32076 use `test`; insert into t1 values( 51 ) +master-bin.000001 32076 Query 1 32166 use `test`; insert into t1 values( 50 ) +master-bin.000001 32166 Query 1 32256 use `test`; insert into t1 values( 49 ) +master-bin.000001 32256 Query 1 32346 use `test`; insert into t1 values( 48 ) +master-bin.000001 32346 Query 1 32436 use `test`; insert into t1 values( 47 ) +master-bin.000001 32436 Query 1 32526 use `test`; insert into t1 values( 46 ) +master-bin.000001 32526 Query 1 32616 use `test`; insert into t1 values( 45 ) +master-bin.000001 32616 Query 1 32706 use `test`; insert into t1 values( 44 ) +master-bin.000001 32706 Query 1 32796 use `test`; insert into t1 values( 43 ) +master-bin.000001 32796 Query 1 32886 use `test`; insert into t1 values( 42 ) +master-bin.000001 32886 Query 1 32976 use `test`; insert into t1 values( 41 ) +master-bin.000001 32976 Query 1 33066 use `test`; insert into t1 values( 40 ) +master-bin.000001 33066 Query 1 33156 use `test`; insert into t1 values( 39 ) +master-bin.000001 33156 Query 1 33246 use `test`; insert into t1 values( 38 ) +master-bin.000001 33246 Query 1 33336 use `test`; insert into t1 values( 37 ) +master-bin.000001 33336 Query 1 33426 use `test`; insert into t1 values( 36 ) +master-bin.000001 33426 Query 1 33516 use `test`; insert into t1 values( 35 ) +master-bin.000001 33516 Query 1 33606 use `test`; insert into t1 values( 34 ) +master-bin.000001 33606 Query 1 33696 use `test`; insert into t1 values( 33 ) +master-bin.000001 33696 Query 1 33786 use `test`; insert into t1 values( 32 ) +master-bin.000001 33786 Query 1 33876 use `test`; insert into t1 values( 31 ) +master-bin.000001 33876 Query 1 33966 use `test`; insert into t1 values( 30 ) +master-bin.000001 33966 Query 1 34056 use `test`; insert into t1 values( 29 ) +master-bin.000001 34056 Query 1 34146 use `test`; insert into t1 values( 28 ) +master-bin.000001 34146 Query 1 34236 use `test`; insert into t1 values( 27 ) +master-bin.000001 34236 Query 1 34326 use `test`; insert into t1 values( 26 ) +master-bin.000001 34326 Query 1 34416 use `test`; insert into t1 values( 25 ) +master-bin.000001 34416 Query 1 34506 use `test`; insert into t1 values( 24 ) +master-bin.000001 34506 Query 1 34596 use `test`; insert into t1 values( 23 ) +master-bin.000001 34596 Query 1 34686 use `test`; insert into t1 values( 22 ) +master-bin.000001 34686 Query 1 34776 use `test`; insert into t1 values( 21 ) +master-bin.000001 34776 Query 1 34866 use `test`; insert into t1 values( 20 ) +master-bin.000001 34866 Query 1 34956 use `test`; insert into t1 values( 19 ) +master-bin.000001 34956 Query 1 35046 use `test`; insert into t1 values( 18 ) +master-bin.000001 35046 Query 1 35136 use `test`; insert into t1 values( 17 ) +master-bin.000001 35136 Query 1 35226 use `test`; insert into t1 values( 16 ) +master-bin.000001 35226 Query 1 35316 use `test`; insert into t1 values( 15 ) +master-bin.000001 35316 Query 1 35406 use `test`; insert into t1 values( 14 ) +master-bin.000001 35406 Query 1 35496 use `test`; insert into t1 values( 13 ) +master-bin.000001 35496 Query 1 35586 use `test`; insert into t1 values( 12 ) +master-bin.000001 35586 Query 1 35676 use `test`; insert into t1 values( 11 ) +master-bin.000001 35676 Query 1 35766 use `test`; insert into t1 values( 10 ) +master-bin.000001 35766 Query 1 35855 use `test`; insert into t1 values( 9 ) +master-bin.000001 35855 Query 1 35944 use `test`; insert into t1 values( 8 ) +master-bin.000001 35944 Query 1 36033 use `test`; insert into t1 values( 7 ) +master-bin.000001 36033 Query 1 36122 use `test`; insert into t1 values( 6 ) +master-bin.000001 36122 Query 1 36211 use `test`; insert into t1 values( 5 ) +master-bin.000001 36211 Query 1 36300 use `test`; insert into t1 values( 4 ) +master-bin.000001 36300 Query 1 36389 use `test`; insert into t1 values( 3 ) +master-bin.000001 36389 Query 1 36478 use `test`; insert into t1 values( 2 ) +master-bin.000001 36478 Query 1 36567 use `test`; insert into t1 values( 1 ) +master-bin.000001 36567 Xid 1 36594 COMMIT /* XID */ +master-bin.000001 36594 Rotate 1 36638 master-bin.000002;pos=4 drop table t1; set global binlog_cache_size=@bcs; set session autocommit = @ac; @@ -590,10 +590,10 @@ deallocate prepare stmt; drop table t1; show binlog events from 0; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4 -master-bin.000001 106 Query 1 227 use `test`; create table t1 (a bigint unsigned, b bigint(20) unsigned) -master-bin.000001 227 Query 1 351 use `test`; insert into t1 values (9999999999999999,14632475938453979136) -master-bin.000001 351 Query 1 427 use `test`; drop table t1 +master-bin.000001 4 Format_desc 1 107 Server version, Binlog ver: 4 +master-bin.000001 107 Query 1 228 use `test`; create table t1 (a bigint unsigned, b bigint(20) unsigned) +master-bin.000001 228 Query 1 352 use `test`; insert into t1 values (9999999999999999,14632475938453979136) +master-bin.000001 352 Query 1 428 use `test`; drop table t1 reset master; CREATE DATABASE bug39182 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; USE bug39182; diff --git a/mysql-test/suite/binlog/t/binlog_incident.test b/mysql-test/suite/binlog/t/binlog_incident.test index 208c7f24df2..37566e71b53 100644 --- a/mysql-test/suite/binlog/t/binlog_incident.test +++ b/mysql-test/suite/binlog/t/binlog_incident.test @@ -19,9 +19,9 @@ REPLACE INTO t1 VALUES (4); DROP TABLE t1; FLUSH LOGS; -exec $MYSQL_BINLOG --start-position=106 $MYSQLD_DATADIR/master-bin.000001 >$MYSQLTEST_VARDIR/tmp/binlog_incident-bug44442.sql; +exec $MYSQL_BINLOG --start-position=107 $MYSQLD_DATADIR/master-bin.000001 >$MYSQLTEST_VARDIR/tmp/binlog_incident-bug44442.sql; --disable_query_log eval SELECT cont LIKE '%RELOAD DATABASE; # Shall generate syntax error%' AS `Contain RELOAD DATABASE` FROM (SELECT load_file('$MYSQLTEST_VARDIR/tmp/binlog_incident-bug44442.sql') AS cont) AS tbl; --enable_query_log -remove_file $MYSQLTEST_VARDIR/tmp/binlog_incident-bug44442.sql; \ No newline at end of file +remove_file $MYSQLTEST_VARDIR/tmp/binlog_incident-bug44442.sql; diff --git a/mysql-test/suite/rpl/r/rpl_000015.result b/mysql-test/suite/rpl/r/rpl_000015.result index 03b96d5870b..d6cb544df7c 100644 --- a/mysql-test/suite/rpl/r/rpl_000015.result +++ b/mysql-test/suite/rpl/r/rpl_000015.result @@ -44,6 +44,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 0 change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=MASTER_PORT; SHOW SLAVE STATUS; @@ -85,6 +87,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 0 start slave; SHOW SLAVE STATUS; Slave_IO_State # @@ -125,6 +129,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 drop table if exists t1; create table t1 (n int, PRIMARY KEY(n)); insert into t1 values (10),(45),(90); diff --git a/mysql-test/suite/rpl/r/rpl_bug33931.result b/mysql-test/suite/rpl/r/rpl_bug33931.result index a17941f6ba9..ba3c3ebafe6 100644 --- a/mysql-test/suite/rpl/r/rpl_bug33931.result +++ b/mysql-test/suite/rpl/r/rpl_bug33931.result @@ -43,4 +43,6 @@ Last_IO_Errno 0 Last_IO_Error Last_SQL_Errno # Last_SQL_Error Failed during slave thread initialization +Replicate_Ignore_Server_Ids +Master_Server_Id 0 SET GLOBAL debug=""; diff --git a/mysql-test/suite/rpl/r/rpl_change_master.result b/mysql-test/suite/rpl/r/rpl_change_master.result index c06c1201e3d..7bc5473c46e 100644 --- a/mysql-test/suite/rpl/r/rpl_change_master.result +++ b/mysql-test/suite/rpl/r/rpl_change_master.result @@ -50,6 +50,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 change master to master_user='root'; SHOW SLAVE STATUS; Slave_IO_State # @@ -90,6 +92,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 start slave; select * from t1; n diff --git a/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result b/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result index 9b54498d809..25c31675b53 100644 --- a/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result @@ -89,6 +89,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 *** Test lock wait timeout *** include/stop_slave.inc @@ -151,6 +153,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 *** Test lock wait timeout and purged relay logs *** SET @my_max_relay_log_size= @@global.max_relay_log_size; @@ -218,6 +222,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 *** Clean up *** DROP TABLE t1,t2,t3; diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result index fd208055bea..9f30d44eeab 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result @@ -93,6 +93,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; SELECT * FROM t2 ORDER BY a; @@ -160,6 +162,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t3 *** @@ -222,6 +226,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t4 *** @@ -284,6 +290,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t5 *** @@ -345,6 +353,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3; *** Drop t6 *** DROP TABLE t6; @@ -454,6 +464,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1364 Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 331 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Create t10 on slave *** @@ -513,6 +525,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t10 *** @@ -574,6 +588,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t11 *** @@ -824,6 +840,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** @@ -964,6 +982,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; ** DROP table t17 *** diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result index e50caa8861e..6f4dad3628b 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result @@ -93,6 +93,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; SELECT * FROM t2 ORDER BY a; @@ -160,6 +162,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t3 *** @@ -222,6 +226,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t4 *** @@ -284,6 +290,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t5 *** @@ -345,6 +353,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3; *** Drop t6 *** DROP TABLE t6; @@ -454,6 +464,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1364 Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 331 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Create t10 on slave *** @@ -513,6 +525,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t10 *** @@ -574,6 +588,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t11 *** @@ -824,6 +840,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** @@ -964,6 +982,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; ** DROP table t17 *** diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result index ad67f96db71..ffc42c852be 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result @@ -133,6 +133,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 ***** Testing Altering table def scenario ***** @@ -509,6 +511,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 **************************************** * columns in master at middle of table * @@ -583,6 +587,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -658,6 +664,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -809,6 +817,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1091 Last_SQL_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -895,6 +905,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1054 Last_SQL_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -981,6 +993,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1072 Last_SQL_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -1274,6 +1288,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 ***** Testing Altering table def scenario ***** @@ -1650,6 +1666,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 **************************************** * columns in master at middle of table * @@ -1724,6 +1742,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1799,6 +1819,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1950,6 +1972,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1091 Last_SQL_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -2036,6 +2060,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1054 Last_SQL_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -2122,6 +2148,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1072 Last_SQL_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -2415,6 +2443,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 ***** Testing Altering table def scenario ***** @@ -2791,6 +2821,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 **************************************** * columns in master at middle of table * @@ -2865,6 +2897,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -2940,6 +2974,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -3091,6 +3127,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1091 Last_SQL_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -3177,6 +3215,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1054 Last_SQL_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -3263,6 +3303,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1072 Last_SQL_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result index 8859a8e24e3..0c3dd7ed21d 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result @@ -133,6 +133,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 ***** Testing Altering table def scenario ***** @@ -509,6 +511,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 **************************************** * columns in master at middle of table * @@ -583,6 +587,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -658,6 +664,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -809,6 +817,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1091 Last_SQL_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -895,6 +905,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1054 Last_SQL_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -981,6 +993,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1072 Last_SQL_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -1274,6 +1288,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 ***** Testing Altering table def scenario ***** @@ -1650,6 +1666,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 **************************************** * columns in master at middle of table * @@ -1724,6 +1742,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1799,6 +1819,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -1950,6 +1972,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1091 Last_SQL_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -2036,6 +2060,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1054 Last_SQL_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -2122,6 +2148,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1072 Last_SQL_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -2415,6 +2443,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 ***** Testing Altering table def scenario ***** @@ -2791,6 +2821,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 **************************************** * columns in master at middle of table * @@ -2865,6 +2897,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -2940,6 +2974,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; @@ -3091,6 +3127,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1091 Last_SQL_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -3177,6 +3215,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1054 Last_SQL_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; @@ -3263,6 +3303,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1072 Last_SQL_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_flushlog_loop.result b/mysql-test/suite/rpl/r/rpl_flushlog_loop.result index 600ac44fc86..3ebd1ac27a4 100644 --- a/mysql-test/suite/rpl/r/rpl_flushlog_loop.result +++ b/mysql-test/suite/rpl/r/rpl_flushlog_loop.result @@ -59,3 +59,5 @@ Last_IO_Errno # Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 2 diff --git a/mysql-test/suite/rpl/r/rpl_grant.result b/mysql-test/suite/rpl/r/rpl_grant.result index 1bed6101e3c..fc32dcefec7 100644 --- a/mysql-test/suite/rpl/r/rpl_grant.result +++ b/mysql-test/suite/rpl/r/rpl_grant.result @@ -80,3 +80,5 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat.result b/mysql-test/suite/rpl/r/rpl_heartbeat.result index 5775351c33d..3bd2ad108ca 100644 --- a/mysql-test/suite/rpl/r/rpl_heartbeat.result +++ b/mysql-test/suite/rpl/r/rpl_heartbeat.result @@ -92,6 +92,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SHOW SLAVE STATUS; Slave_IO_State # Master_Host 127.0.0.1 @@ -131,6 +133,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 show status like 'Slave_heartbeat_period';; Variable_name Slave_heartbeat_period Value 0.500 diff --git a/mysql-test/suite/rpl/r/rpl_incident.result b/mysql-test/suite/rpl/r/rpl_incident.result index c3baabbdbc3..a9b641b243b 100644 --- a/mysql-test/suite/rpl/r/rpl_incident.result +++ b/mysql-test/suite/rpl/r/rpl_incident.result @@ -64,6 +64,8 @@ Last_IO_Errno 0 Last_IO_Error Last_SQL_Errno 1590 Last_SQL_Error The incident LOST_EVENTS occured on the master. Message: +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; SELECT * FROM t1; @@ -111,4 +113,6 @@ Last_IO_Errno 0 Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 DROP TABLE t1; diff --git a/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result b/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result index 3055216cbd9..7f346070290 100644 --- a/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result +++ b/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result @@ -50,6 +50,8 @@ Last_IO_Errno 0 Last_IO_Error Last_SQL_Errno 1105 Last_SQL_Error Error 'master may suffer from http://bugs.mysql.com/bug.php?id=24432 so slave stops; check error log on slave for more info' on query. Default database: 'test'. Query: 'INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT * FROM t1; a b stop slave; @@ -141,6 +143,8 @@ SELECT t2.field_a, t2.field_b, t2.field_c FROM t2 ON DUPLICATE KEY UPDATE t1.field_3 = t2.field_c' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT * FROM t1; id field_1 field_2 field_3 drop table t1, t2; diff --git a/mysql-test/suite/rpl/r/rpl_loaddata.result b/mysql-test/suite/rpl/r/rpl_loaddata.result index 141bbaeb95e..35fac3bd076 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata.result @@ -73,6 +73,8 @@ Last_IO_Errno 0 Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 set sql_log_bin=0; delete from t1; set sql_log_bin=1; @@ -119,6 +121,8 @@ Last_IO_Errno 0 Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 set global sql_slave_skip_counter=1; start slave; set sql_log_bin=0; @@ -166,6 +170,8 @@ Last_IO_Errno 0 Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 reset master; create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), unique(day)) engine=MyISAM; diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result index cb2accc86ca..bbf4b9f97d4 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result @@ -45,6 +45,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE t1; SHOW SLAVE STATUS; Slave_IO_State # @@ -85,6 +87,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1593 Last_SQL_Error Fatal error: Not enough memory +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; DROP TABLE t1; diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 7b3ebf62959..e490468059d 100644 --- a/mysql-test/suite/rpl/r/rpl_log_pos.result +++ b/mysql-test/suite/rpl/r/rpl_log_pos.result @@ -48,6 +48,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 start slave; include/stop_slave.inc SHOW SLAVE STATUS; @@ -89,6 +91,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 # diff --git a/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result b/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result index 59726ea5661..53e8899d27f 100644 --- a/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result +++ b/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result @@ -63,6 +63,8 @@ Last_IO_Errno # Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info slave-bin.000001 # Format_desc 2 # Server ver: VERSION, Binlog ver: 4 diff --git a/mysql-test/suite/rpl/r/rpl_replicate_do.result b/mysql-test/suite/rpl/r/rpl_replicate_do.result index 33088ee2ec8..2fbd283a9c8 100644 --- a/mysql-test/suite/rpl/r/rpl_replicate_do.result +++ b/mysql-test/suite/rpl/r/rpl_replicate_do.result @@ -65,6 +65,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 create table t1 (ts timestamp); set one_shot time_zone='met'; insert into t1 values('2005-08-12 00:00:00'); diff --git a/mysql-test/suite/rpl/r/rpl_rotate_logs.result b/mysql-test/suite/rpl/r/rpl_rotate_logs.result index 013ba87ec0b..b3b1480a740 100644 --- a/mysql-test/suite/rpl/r/rpl_rotate_logs.result +++ b/mysql-test/suite/rpl/r/rpl_rotate_logs.result @@ -53,6 +53,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 select * from t1; s Could not break slave @@ -132,6 +134,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 select * from t2; m 34 @@ -196,6 +200,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 lock tables t3 read; select count(*) from t3 where n >= 4; count(*) diff --git a/mysql-test/suite/rpl/r/rpl_row_colSize.result b/mysql-test/suite/rpl/r/rpl_row_colSize.result index 6d002a722f1..acda689ca9b 100644 --- a/mysql-test/suite/rpl/r/rpl_row_colSize.result +++ b/mysql-test/suite/rpl/r/rpl_row_colSize.result @@ -57,6 +57,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -111,6 +113,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 12, test.t1 on slave has size 12. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -165,6 +169,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 10, test.t1 on slave has size 3. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -220,6 +226,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 5, test.t1 has type 4 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -275,6 +283,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 8, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -329,6 +339,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 2. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -384,6 +396,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -439,6 +453,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 20, test.t1 on slave has size 11. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -525,6 +541,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -580,6 +598,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 100. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -634,6 +654,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 200, test.t1 on slave has size 10. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -688,6 +710,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 2000, test.t1 on slave has size 1000. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 @@ -743,6 +767,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 size mismatch - master has size 4, test.t1 on slave has size 1. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT COUNT(*) FROM t1; COUNT(*) 0 diff --git a/mysql-test/suite/rpl/r/rpl_row_log.result b/mysql-test/suite/rpl/r/rpl_row_log.result index ca8fba3b6bd..789db064eb5 100644 --- a/mysql-test/suite/rpl/r/rpl_row_log.result +++ b/mysql-test/suite/rpl/r/rpl_row_log.result @@ -283,6 +283,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 show binlog events in 'slave-bin.000005' from 4; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log DROP TABLE t1; diff --git a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result index 9347f87ef8f..fbd9f685ba9 100644 --- a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result @@ -283,6 +283,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 show binlog events in 'slave-bin.000005' from 4; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log DROP TABLE t1; diff --git a/mysql-test/suite/rpl/r/rpl_row_max_relay_size.result b/mysql-test/suite/rpl/r/rpl_row_max_relay_size.result index 2215b34814e..c2554218f73 100644 --- a/mysql-test/suite/rpl/r/rpl_row_max_relay_size.result +++ b/mysql-test/suite/rpl/r/rpl_row_max_relay_size.result @@ -60,6 +60,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 2 # @@ -108,6 +110,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 3: max_relay_log_size = 0 # @@ -156,6 +160,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 4: Tests below are mainly to ensure that we have not coded with wrong assumptions # @@ -201,6 +207,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 5 # @@ -247,6 +255,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 6: one more rotation, to be sure Relay_Log_Space is correctly updated # @@ -291,6 +301,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 flush logs; show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/suite/rpl/r/rpl_row_reset_slave.result b/mysql-test/suite/rpl/r/rpl_row_reset_slave.result index fa40d8760a8..501749e12f9 100644 --- a/mysql-test/suite/rpl/r/rpl_row_reset_slave.result +++ b/mysql-test/suite/rpl/r/rpl_row_reset_slave.result @@ -43,6 +43,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 stop slave; change master to master_user='test'; SHOW SLAVE STATUS; @@ -84,6 +86,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 reset slave; SHOW SLAVE STATUS; Slave_IO_State # @@ -124,6 +128,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 start slave; SHOW SLAVE STATUS; Slave_IO_State # @@ -164,6 +170,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 stop slave; reset slave; start slave; diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result index a6a2181cd2a..4cb632da9e1 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result @@ -144,6 +144,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 1364 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (2); @@ -195,6 +197,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 INSERT INTO t9 VALUES (4); INSERT INTO t4 VALUES (4); SHOW SLAVE STATUS; @@ -236,6 +240,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 1535 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (5); @@ -279,6 +285,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 1535 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (6); @@ -322,6 +330,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 1535 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (6); @@ -364,6 +374,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 INSERT INTO t7 VALUES (1),(2),(3); INSERT INTO t8 VALUES (1),(2),(3); SELECT * FROM t7 ORDER BY a; diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result index 02e8c074354..a293bfed0d5 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result @@ -144,6 +144,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 1364 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (2); @@ -195,6 +197,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 INSERT INTO t9 VALUES (4); INSERT INTO t4 VALUES (4); SHOW SLAVE STATUS; @@ -236,6 +240,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 1535 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (5); @@ -279,6 +285,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 1535 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (6); @@ -322,6 +330,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 1535 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (6); @@ -364,6 +374,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 INSERT INTO t7 VALUES (1),(2),(3); INSERT INTO t8 VALUES (1),(2),(3); SELECT * FROM t7 ORDER BY a; diff --git a/mysql-test/suite/rpl/r/rpl_row_until.result b/mysql-test/suite/rpl/r/rpl_row_until.result index ad54450af74..e878456e296 100644 --- a/mysql-test/suite/rpl/r/rpl_row_until.result +++ b/mysql-test/suite/rpl/r/rpl_row_until.result @@ -59,6 +59,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 START SLAVE UNTIL MASTER_LOG_FILE='master-no-such-bin.000001', MASTER_LOG_POS=291; SELECT * FROM t1; n @@ -105,6 +107,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 START SLAVE UNTIL RELAY_LOG_FILE='slave-relay-bin.000002', RELAY_LOG_POS=relay_pos_insert1_t2 SELECT * FROM t2; n @@ -149,6 +153,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 START SLAVE; include/stop_slave.inc START SLAVE SQL_THREAD UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=master_pos_create_t2 @@ -191,6 +197,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 START SLAVE UNTIL MASTER_LOG_FILE='master-bin', MASTER_LOG_POS=561; ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UNTIL START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=561, RELAY_LOG_POS=12; diff --git a/mysql-test/suite/rpl/r/rpl_skip_error.result b/mysql-test/suite/rpl/r/rpl_skip_error.result index d955859f030..7b2bd48515d 100644 --- a/mysql-test/suite/rpl/r/rpl_skip_error.result +++ b/mysql-test/suite/rpl/r/rpl_skip_error.result @@ -70,6 +70,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 ==== Clean Up ==== drop table t1; create table t1(a int primary key); @@ -123,6 +125,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 ==== Clean Up ==== drop table t1; ==== Using Innodb ==== diff --git a/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result b/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result index e2efcf08d7a..880fc9e8569 100644 --- a/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result +++ b/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result @@ -49,6 +49,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 9 Last_SQL_Error Error in Begin_load_query event: write to '../../tmp/SQL_LOAD.data' failed +Replicate_Ignore_Server_Ids +Master_Server_Id 1 drop table t1; drop table t1; call mtr.add_suppression("Slave: Error writing file 'UNKNOWN' .Errcode: 9. Error_code: 3"); diff --git a/mysql-test/suite/rpl/r/rpl_slave_skip.result b/mysql-test/suite/rpl/r/rpl_slave_skip.result index 41076f9fee3..5a37344cac6 100644 --- a/mysql-test/suite/rpl/r/rpl_slave_skip.result +++ b/mysql-test/suite/rpl/r/rpl_slave_skip.result @@ -82,6 +82,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; SELECT * FROM t1; @@ -146,6 +148,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 **** On Master **** DROP TABLE t1, t2; SET SESSION BINLOG_FORMAT=ROW; diff --git a/mysql-test/suite/rpl/r/rpl_ssl.result b/mysql-test/suite/rpl/r/rpl_ssl.result index d188dd353ce..c8e9e1a4911 100644 --- a/mysql-test/suite/rpl/r/rpl_ssl.result +++ b/mysql-test/suite/rpl/r/rpl_ssl.result @@ -58,6 +58,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; select * from t1; t @@ -102,6 +104,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 drop user replssl@localhost; drop table t1; End of 5.0 tests diff --git a/mysql-test/suite/rpl/r/rpl_ssl1.result b/mysql-test/suite/rpl/r/rpl_ssl1.result index 74d2550cdaf..de255228aff 100644 --- a/mysql-test/suite/rpl/r/rpl_ssl1.result +++ b/mysql-test/suite/rpl/r/rpl_ssl1.result @@ -57,6 +57,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 stop slave; change master to master_user='root',master_password='', master_ssl=0; start slave; @@ -101,6 +103,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 stop slave; change master to master_host="localhost", @@ -155,4 +159,6 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 drop table t1; diff --git a/mysql-test/suite/rpl/r/rpl_stm_log.result b/mysql-test/suite/rpl/r/rpl_stm_log.result index 61eba2b4b3f..97dfbb618e2 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_log.result +++ b/mysql-test/suite/rpl/r/rpl_stm_log.result @@ -265,6 +265,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 show binlog events in 'slave-bin.000005' from 4; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log DROP TABLE t1; diff --git a/mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result b/mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result index 2215b34814e..c2554218f73 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result +++ b/mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result @@ -60,6 +60,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 2 # @@ -108,6 +110,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 3: max_relay_log_size = 0 # @@ -156,6 +160,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 4: Tests below are mainly to ensure that we have not coded with wrong assumptions # @@ -201,6 +207,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 5 # @@ -247,6 +255,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 # # Test 6: one more rotation, to be sure Relay_Log_Space is correctly updated # @@ -291,6 +301,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 flush logs; show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/suite/rpl/r/rpl_stm_reset_slave.result b/mysql-test/suite/rpl/r/rpl_stm_reset_slave.result index 78d9d7c41eb..d18ca563b7b 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_reset_slave.result +++ b/mysql-test/suite/rpl/r/rpl_stm_reset_slave.result @@ -43,6 +43,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 stop slave; change master to master_user='test'; SHOW SLAVE STATUS; @@ -84,6 +86,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 reset slave; SHOW SLAVE STATUS; Slave_IO_State # @@ -124,6 +128,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 start slave; SHOW SLAVE STATUS; Slave_IO_State # @@ -164,6 +170,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 stop slave; reset slave; start slave; diff --git a/mysql-test/suite/rpl/r/rpl_stm_until.result b/mysql-test/suite/rpl/r/rpl_stm_until.result index 55074f0be0d..6af9be0da3b 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_until.result +++ b/mysql-test/suite/rpl/r/rpl_stm_until.result @@ -63,6 +63,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291; select * from t1; n @@ -109,6 +111,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746; select * from t2; n @@ -153,6 +157,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 start slave; [on master] [on slave] @@ -197,6 +203,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 ==== Test various error conditions ==== start slave until master_log_file='master-bin', master_log_pos=561; ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UNTIL diff --git a/mysql-test/suite/rpl/r/rpl_temporary_errors.result b/mysql-test/suite/rpl/r/rpl_temporary_errors.result index d14380a6369..f4626304fc3 100644 --- a/mysql-test/suite/rpl/r/rpl_temporary_errors.result +++ b/mysql-test/suite/rpl/r/rpl_temporary_errors.result @@ -79,6 +79,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 DROP TABLE t1; **** On Master **** DROP TABLE t1; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_basic.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_basic.result index b16a63ec5ad..6680f3fd70f 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_basic.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_basic.result @@ -179,6 +179,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 set GLOBAL slave_transaction_retries=10; include/start_slave.inc select * from t1 order by nid; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular.result index 2daacb351a9..aeb9e215d15 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular.result @@ -56,6 +56,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT * FROM t1 ORDER BY a; a b 1 2 @@ -99,5 +101,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 2 STOP SLAVE; DROP TABLE t1; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result index 01f8d94da48..19439c4c0e1 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result @@ -53,6 +53,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 2 SELECT * FROM t1 ORDER BY a; a b 1 2 @@ -102,3 +104,5 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result index f812509de6f..771f44e4279 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result @@ -93,6 +93,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 size mismatch - master has size 10, test.t2 on slave has size 6. Master's column size should be <= the slave's column size. +Replicate_Ignore_Server_Ids +Master_Server_Id 1 STOP SLAVE; RESET SLAVE; SELECT * FROM t2 ORDER BY a; @@ -160,6 +162,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 252, test.t3 has type 3 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t3 *** @@ -222,6 +226,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 246, test.t4 has type 3 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t4 *** @@ -284,6 +290,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 5 type mismatch - received type 4, test.t5 has type 246 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t5 *** @@ -345,6 +353,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 3 type mismatch - received type 16, test.t6 has type 3 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3; *** Drop t6 *** DROP TABLE t6; @@ -454,6 +464,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1364 Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's master log master-bin.000001, end_log_pos 447 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Create t10 on slave *** @@ -513,6 +525,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 254, test.t10 has type 5 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t10 *** @@ -574,6 +588,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 15, test.t11 has type 252 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; *** Drop t11 *** @@ -824,6 +840,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** @@ -964,6 +982,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1535 Last_SQL_Error Table definition on master and slave does not match: Column 0 type mismatch - received type 8, test.t17 has type 2 +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; ** DROP table t17 *** diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_idempotent.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_idempotent.result index e2fee391bab..2df70ace0c1 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_idempotent.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_idempotent.result @@ -33,15 +33,15 @@ c1 c2 c3 row3 C 3 row4 D 4 SHOW SLAVE STATUS; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error - 127.0.0.1 root MASTER_PORT 1 master-bin.000001 master-bin.000001 Yes Yes 0 0 None 0 No No 0 +Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id + 127.0.0.1 root MASTER_PORT 1 master-bin.000001 master-bin.000001 Yes Yes 0 0 None 0 No No 0 1 STOP SLAVE; CHANGE MASTER TO master_log_file = 'master-bin.000001', master_log_pos = ; SHOW SLAVE STATUS; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error - 127.0.0.1 root MASTER_PORT 1 master-bin.000001 master-bin.000001 No No 0 0 None 0 No No 0 +Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id + 127.0.0.1 root MASTER_PORT 1 master-bin.000001 master-bin.000001 No No 0 0 None 0 No No 0 1 START SLAVE; SELECT * FROM t1 ORDER BY c3; c1 c2 c3 @@ -68,6 +68,6 @@ SELECT * FROM t1; c1 c2 c3 row2 new on slave 2 SHOW SLAVE STATUS; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error - 127.0.0.1 root MASTER_PORT 1 master-bin.000001 master-bin.000001 Yes Yes 0 0 None 0 No 0 +Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error Replicate_Ignore_Server_Ids Master_Server_Id + 127.0.0.1 root MASTER_PORT 1 master-bin.000001 master-bin.000001 Yes Yes 0 0 None 0 No 0 1 DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_sync.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_sync.result index 3ef5e2b7e53..b61f5550719 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_sync.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_sync.result @@ -107,6 +107,8 @@ Last_IO_Errno Last_IO_Error Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 SELECT hex(c1),hex(c2),c3 FROM t1 ORDER BY c3; hex(c1) hex(c2) c3 1 1 row1 diff --git a/mysql-test/t/ctype_cp932_binlog_stm.test b/mysql-test/t/ctype_cp932_binlog_stm.test index 19f44695f28..af6e6baf92a 100644 --- a/mysql-test/t/ctype_cp932_binlog_stm.test +++ b/mysql-test/t/ctype_cp932_binlog_stm.test @@ -33,7 +33,7 @@ delimiter ;| # the log's contents) that caused the server crash. --error 1220 -SHOW BINLOG EVENTS FROM 365; +SHOW BINLOG EVENTS FROM 366; --echo Bug#44352 UPPER/LOWER function doesn't work correctly on cp932 and sjis environment. CREATE TABLE t1 (a varchar(16)) character set cp932; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 597c9671053..015d4d152cb 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -119,7 +119,7 @@ select "--- reading stdin --" as ""; --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ ---exec $MYSQL_BINLOG --short-form --position=80 - < $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 +--exec $MYSQL_BINLOG --short-form --position=79 - < $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 drop table t1,t2; # diff --git a/sql/lex.h b/sql/lex.h index 790808a8c14..0a61a92fd60 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -244,6 +244,7 @@ static SYMBOL symbols[] = { { "IDENTIFIED", SYM(IDENTIFIED_SYM)}, { "IF", SYM(IF)}, { "IGNORE", SYM(IGNORE_SYM)}, + { "IGNORE_SERVER_IDS", SYM(IGNORE_SERVER_IDS_SYM)}, { "IMPORT", SYM(IMPORT)}, { "IN", SYM(IN_SYM)}, { "INDEX", SYM(INDEX_SYM)}, diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 77f7b7e1929..a50f75d53e3 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -27,17 +27,19 @@ int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val); int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val); +int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f); Master_info::Master_info() :Slave_reporting_capability("I/O"), ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), inited(0), abort_slave(0),slave_running(0), slave_run_id(0), - heartbeat_period(0), received_heartbeats(0) + heartbeat_period(0), received_heartbeats(0), master_id(0) { host[0] = 0; user[0] = 0; password[0] = 0; ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; ssl_cipher[0]= 0; ssl_key[0]= 0; + my_init_dynamic_array(&ignore_server_ids, sizeof(::server_id), 16, 16); bzero((char*) &file, sizeof(file)); pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); @@ -48,6 +50,7 @@ Master_info::Master_info() Master_info::~Master_info() { + delete_dynamic(&ignore_server_ids); pthread_mutex_destroy(&run_lock); pthread_mutex_destroy(&data_lock); pthread_cond_destroy(&data_cond); @@ -55,6 +58,43 @@ Master_info::~Master_info() pthread_cond_destroy(&stop_cond); } +/** + A comparison function to be supplied as argument to @c sort_dynamic() + and @c bsearch() + + @return -1 if first argument is less, 0 if it equal to, 1 if it is greater + than the second +*/ +int change_master_server_id_cmp(ulong *id1, ulong *id2) +{ + return *id1 < *id2? -1 : (*id1 > *id2? 1 : 0); +} + + +/** + Reports if the s_id server has been configured to ignore events + it generates with + + CHANGE MASTER IGNORE_SERVER_IDS= ( list of server ids ) + + Method is called from the io thread event receiver filtering. + + @param s_id the master server identifier + + @retval TRUE if s_id is in the list of ignored master servers, + @retval FALSE otherwise. + */ +bool Master_info::shall_ignore_server_id(ulong s_id) +{ + if (likely(ignore_server_ids.elements == 1)) + return (* (ulong*) dynamic_array_ptr(&ignore_server_ids, 0)) == s_id; + else + return bsearch((const ulong *) &s_id, + ignore_server_ids.buffer, + ignore_server_ids.elements, sizeof(ulong), + (int (*) (const void*, const void*)) change_master_server_id_cmp) + != NULL; +} void init_master_info_with_options(Master_info* mi) { @@ -105,12 +145,12 @@ enum { /* 5.1.16 added value of master_ssl_verify_server_cert */ LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15, - /* 6.0 added value of master_heartbeat_period */ LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16, - + /* 6.0 added value of master_ignore_server_id */ + LINE_FOR_REPLICATE_IGNORE_SERVER_IDS= 17, /* Number of lines currently used when saving master info file */ - LINES_IN_MASTER_INFO= LINE_FOR_MASTER_HEARTBEAT_PERIOD + LINES_IN_MASTER_INFO= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS }; int init_master_info(Master_info* mi, const char* master_info_fname, @@ -304,6 +344,16 @@ file '%s')", fname); if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD && init_floatvar_from_file(&master_heartbeat_period, &mi->file, 0.0)) goto errwithmsg; + /* + Starting from 6.0 list of server_id of ignorable servers might be + in the file + */ + if (lines >= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS && + init_dynarray_intvar_from_file(&mi->ignore_server_ids, &mi->file)) + { + sql_print_error("Failed to initialize master info ignore_server_ids"); + goto errwithmsg; + } } #ifndef HAVE_OPENSSL @@ -384,7 +434,29 @@ int flush_master_info(Master_info* mi, bool flush_relay_log_cache) if (flush_relay_log_cache && flush_io_cache(mi->rli.relay_log.get_log_file())) DBUG_RETURN(2); - + + /* + produce a line listing the total number and all the ignored server_id:s + */ + char* ignore_server_ids_buf; + { + ignore_server_ids_buf= + (char *) my_malloc((sizeof(::server_id) * 3 + 1) * + (1 + mi->ignore_server_ids.elements), MYF(MY_WME)); + if (!ignore_server_ids_buf) + DBUG_RETURN(1); + for (ulong i= 0, cur_len= my_sprintf(ignore_server_ids_buf, + (ignore_server_ids_buf, "%u", + mi->ignore_server_ids.elements)); + i < mi->ignore_server_ids.elements; i++) + { + ulong s_id; + get_dynamic(&mi->ignore_server_ids, (uchar*) &s_id, i); + cur_len +=my_sprintf(ignore_server_ids_buf + cur_len, + (ignore_server_ids_buf + cur_len, + " %lu", s_id)); + } + } /* We flushed the relay log BEFORE the master.info file, because if we crash now, we will get a duplicate event in the relay log at restart. If we @@ -405,14 +477,16 @@ int flush_master_info(Master_info* mi, bool flush_relay_log_cache) my_sprintf(heartbeat_buf, (heartbeat_buf, "%.3f", mi->heartbeat_period)); my_b_seek(file, 0L); my_b_printf(file, - "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n", + "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n", LINES_IN_MASTER_INFO, mi->master_log_name, llstr(mi->master_log_pos, lbuf), mi->host, mi->user, mi->password, mi->port, mi->connect_retry, (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert, - heartbeat_buf); + heartbeat_buf, ignore_server_ids_buf); + + my_free(ignore_server_ids_buf, MYF(0)); DBUG_RETURN(-flush_io_cache(file)); } diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index 35e18414932..0caa6904da4 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -20,6 +20,7 @@ #include "rpl_rli.h" #include "rpl_reporting.h" +#include "my_sys.h" /***************************************************************************** @@ -60,6 +61,7 @@ class Master_info : public Slave_reporting_capability public: Master_info(); ~Master_info(); + bool shall_ignore_server_id(ulong s_id); /* the variables below are needed because we can change masters on the fly */ char master_log_name[FN_REFLEN]; @@ -83,8 +85,6 @@ class Master_info : public Slave_reporting_capability Relay_log_info rli; uint port; uint connect_retry; - float heartbeat_period; // interface with CHANGE MASTER or master.info - ulonglong received_heartbeats; // counter of received heartbeat events #ifndef DBUG_OFF int events_till_disconnect; #endif @@ -102,6 +102,10 @@ class Master_info : public Slave_reporting_capability */ long clock_diff_with_master; + float heartbeat_period; // interface with CHANGE MASTER or master.info + ulonglong received_heartbeats; // counter of received heartbeat events + DYNAMIC_ARRAY ignore_server_ids; + ulong master_id; }; void init_master_info_with_options(Master_info* mi); @@ -111,6 +115,7 @@ int init_master_info(Master_info* mi, const char* master_info_fname, int thread_mask); void end_master_info(Master_info* mi); int flush_master_info(Master_info* mi, bool flush_relay_log_cache); +int change_master_server_id_cmp(ulong *id1, ulong *id2); #endif /* HAVE_REPLICATION */ #endif /* RPL_MI_H */ diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 3aba434b284..18d3a41424a 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6163,6 +6163,9 @@ ER_SLAVE_HEARTBEAT_FAILURE ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE eng "The requested value for the heartbeat period %s %s" +ER_SLAVE_IGNORE_SERVER_IDS + eng "The requested server id %d clashes with the slave startup option --replicate-same-server-id" + ER_NDB_REPLICATION_SCHEMA_ERROR eng "Bad schema for mysql.ndb_replication table. Message: %-.64s" ER_CONFLICT_FN_PARSE_ERROR diff --git a/sql/slave.cc b/sql/slave.cc index bbdfb8e633f..fe4a2f6ba0a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -880,6 +880,95 @@ int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val) DBUG_RETURN(1); } + +/** + A master info read method + + This function is called from @c init_master_info() along with + relatives to restore some of @c active_mi members. + Particularly, this function is responsible for restoring + IGNORE_SERVER_IDS list of servers whose events the slave is + going to ignore (to not log them in the relay log). + Items being read are supposed to be decimal output of values of a + type shorter or equal of @c long and separated by the single space. + + @param arr @c DYNAMIC_ARRAY pointer to storage for servers id + @param f @c IO_CACHE pointer to the source file + + @retval 0 All OK + @retval non-zero An error +*/ + +int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f) +{ + int ret= 0; + char buf[16 * (sizeof(long)*4 + 1)]; // static buffer to use most of times + char *buf_act= buf; // actual buffer can be dynamic if static is short + char *token, *last; + uint num_items; // number of items of `arr' + size_t read_size; + DBUG_ENTER("init_dynarray_intvar_from_file"); + + if ((read_size= my_b_gets(f, buf_act, sizeof(buf))) == 0) + { + return 0; // no line in master.info + } + if (read_size + 1 == sizeof(buf) && buf[sizeof(buf) - 2] != '\n') + { + /* + short read happend; allocate sufficient memory and make the 2nd read + */ + char buf_work[(sizeof(long)*3 + 1)*16]; + memcpy(buf_work, buf, sizeof(buf_work)); + num_items= atoi(strtok_r(buf_work, " ", &last)); + size_t snd_size; + /* + max size lower bound approximate estimation bases on the formula: + (the items number + items themselves) * + (decimal size + space) - 1 + `\n' + '\0' + */ + size_t max_size= (1 + num_items) * (sizeof(long)*3 + 1) + 1; + buf_act= (char*) my_malloc(max_size, MYF(MY_WME)); + memcpy(buf_act, buf, read_size); + snd_size= my_b_gets(f, buf_act + read_size, max_size - read_size); + if (snd_size == 0 || + (snd_size + 1 == max_size - read_size) && buf[max_size - 2] != '\n') + { + /* + failure to make the 2nd read or short read again + */ + ret= 1; + goto err; + } + } + token= strtok_r(buf_act, " ", &last); + if (token == NULL) + { + ret= 1; + goto err; + } + num_items= atoi(token); + for (uint i=0; i < num_items; i++) + { + token= strtok_r(NULL, " ", &last); + if (token == NULL) + { + ret= 1; + goto err; + } + else + { + ulong val= atol(token); + insert_dynamic(arr, (uchar *) &val); + } + } +err: + if (buf_act != buf) + my_free(buf_act, MYF(0)); + DBUG_RETURN(ret); +} + + static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info) { if (io_slave_killed(thd, mi)) @@ -1058,7 +1147,7 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) (master_res= mysql_store_result(mysql)) && (master_row= mysql_fetch_row(master_res))) { - if ((::server_id == strtoul(master_row[1], 0, 10)) && + if ((::server_id == (mi->master_id= strtoul(master_row[1], 0, 10))) && !mi->rli.replicate_same_server_id) { errmsg= "The slave I/O thread stops because master and slave have equal \ @@ -1096,6 +1185,13 @@ maybe it is a *VERY OLD MASTER*."); mysql_free_result(master_res); master_res= NULL; } + if (mi->master_id == 0 && mi->ignore_server_ids.elements > 0) + { + errmsg= "Slave configured with server id filtering could not detect the master server id."; + err_code= ER_SLAVE_FATAL_ERROR; + sprintf(err_buff, ER(err_code), errmsg); + goto err; + } /* Check that the master's global character_set_server and ours are the same. @@ -1659,6 +1755,10 @@ bool show_master_info(THD* thd, Master_info* mi) field_list.push_back(new Item_empty_string("Last_IO_Error", 20)); field_list.push_back(new Item_return_int("Last_SQL_Errno", 4, MYSQL_TYPE_LONG)); field_list.push_back(new Item_empty_string("Last_SQL_Error", 20)); + field_list.push_back(new Item_empty_string("Replicate_Ignore_Server_Ids", + FN_REFLEN)); + field_list.push_back(new Item_return_int("Master_Server_Id", sizeof(ulong), + MYSQL_TYPE_LONG)); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) @@ -1780,6 +1880,32 @@ bool show_master_info(THD* thd, Master_info* mi) protocol->store(mi->rli.last_error().number); // Last_SQL_Error protocol->store(mi->rli.last_error().message, &my_charset_bin); + // Replicate_Ignore_Server_Ids + { + char buff[FN_REFLEN]; + ulong i, cur_len; + for (i= 0, buff[0]= 0, cur_len= 0; + i < mi->ignore_server_ids.elements; i++) + { + ulong s_id, slen; + char sbuff[FN_REFLEN]; + get_dynamic(&mi->ignore_server_ids, (uchar*) &s_id, i); + slen= my_sprintf(sbuff, (sbuff, (i==0? "%lu" : ", %lu"), s_id)); + if (cur_len + slen + 4 > FN_REFLEN) + { + /* + break the loop whenever remained space could not fit + ellipses on the next cycle + */ + my_sprintf(buff + cur_len, (buff + cur_len, "...")); + break; + } + cur_len += my_sprintf(buff + cur_len, (buff + cur_len, "%s", sbuff)); + } + protocol->store(buff, &my_charset_bin); + } + // Master_Server_id + protocol->store((uint32) mi->master_id); pthread_mutex_unlock(&mi->rli.err_lock); pthread_mutex_unlock(&mi->err_lock); @@ -3599,6 +3725,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) ulong inc_pos; Relay_log_info *rli= &mi->rli; pthread_mutex_t *log_lock= rli->relay_log.get_log_lock(); + ulong s_id; DBUG_ENTER("queue_event"); LINT_INIT(inc_pos); @@ -3745,9 +3872,20 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) */ pthread_mutex_lock(log_lock); - - if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) && - !mi->rli.replicate_same_server_id) + s_id= uint4korr(buf + SERVER_ID_OFFSET); + if ((s_id == ::server_id && !mi->rli.replicate_same_server_id) || + /* + the following conjunction deals with IGNORE_SERVER_IDS, if set + If the master is on the ignore list, execution of + format description log events and rotate events is necessary. + */ + (mi->ignore_server_ids.elements > 0 && + mi->shall_ignore_server_id(s_id) && + /* everything is filtered out from non-master */ + (s_id != mi->master_id || + /* for the master meta information is necessary */ + buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT && + buf[EVENT_TYPE_OFFSET] != ROTATE_EVENT))) { /* Do not write it to the relay log. @@ -3762,10 +3900,14 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) But events which were generated by this slave and which do not exist in the master's binlog (i.e. Format_desc, Rotate & Stop) should not increment mi->master_log_pos. + If the event is originated remotely and is being filtered out by + IGNORE_SERVER_IDS it increments mi->master_log_pos + as well as rli->group_relay_log_pos. */ - if (buf[EVENT_TYPE_OFFSET]!=FORMAT_DESCRIPTION_EVENT && - buf[EVENT_TYPE_OFFSET]!=ROTATE_EVENT && - buf[EVENT_TYPE_OFFSET]!=STOP_EVENT) + if (!(s_id == ::server_id && !mi->rli.replicate_same_server_id) || + buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT && + buf[EVENT_TYPE_OFFSET] != ROTATE_EVENT && + buf[EVENT_TYPE_OFFSET] != STOP_EVENT) { mi->master_log_pos+= inc_pos; memcpy(rli->ign_master_log_name_end, mi->master_log_name, FN_REFLEN); @@ -3773,8 +3915,8 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) rli->ign_master_log_pos_end= mi->master_log_pos; } rli->relay_log.signal_update(); // the slave SQL thread needs to re-check - DBUG_PRINT("info", ("master_log_pos: %lu, event originating from the same server, ignored", - (ulong) mi->master_log_pos)); + DBUG_PRINT("info", ("master_log_pos: %lu, event originating from %u server, ignored", + (ulong) mi->master_log_pos, uint4korr(buf + SERVER_ID_OFFSET))); } else { diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f6effab93a4..c4ab3091d6a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -214,10 +214,11 @@ typedef struct st_lex_master_info changed variable or if it should be left at old value */ enum {LEX_MI_UNCHANGED, LEX_MI_DISABLE, LEX_MI_ENABLE} - ssl, ssl_verify_server_cert, heartbeat_opt; + ssl, ssl_verify_server_cert, heartbeat_opt, repl_ignore_server_ids_opt; char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher; char *relay_log_name; ulong relay_log_pos; + DYNAMIC_ARRAY repl_ignore_server_ids; } LEX_MASTER_INFO; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index cde713b1b40..eadb3362882 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1266,26 +1266,27 @@ bool change_master(THD* thd, Master_info* mi) int thread_mask; const char* errmsg= 0; bool need_relay_log_purge= 1; + bool ret= FALSE; DBUG_ENTER("change_master"); lock_slave_threads(mi); init_thread_mask(&thread_mask,mi,0 /*not inverse*/); + LEX_MASTER_INFO* lex_mi= &thd->lex->mi; if (thread_mask) // We refuse if any slave thread is running { my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0)); - unlock_slave_threads(mi); - DBUG_RETURN(TRUE); + ret= TRUE; + goto err; } thd_proc_info(thd, "Changing master"); - LEX_MASTER_INFO* lex_mi= &thd->lex->mi; // TODO: see if needs re-write if (init_master_info(mi, master_info_file, relay_log_info_file, 0, thread_mask)) { my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0)); - unlock_slave_threads(mi); - DBUG_RETURN(TRUE); + ret= TRUE; + goto err; } /* @@ -1330,6 +1331,34 @@ bool change_master(THD* thd, Master_info* mi) mi->heartbeat_period= (float) min(SLAVE_MAX_HEARTBEAT_PERIOD, (slave_net_timeout/2.0)); mi->received_heartbeats= LL(0); // counter lives until master is CHANGEd + /* + reset the last time server_id list if the current CHANGE MASTER + is mentioning IGNORE_SERVER_IDS= (...) + */ + if (lex_mi->repl_ignore_server_ids_opt == LEX_MASTER_INFO::LEX_MI_ENABLE) + reset_dynamic(&mi->ignore_server_ids); + for (uint i= 0; i < lex_mi->repl_ignore_server_ids.elements; i++) + { + ulong s_id; + get_dynamic(&lex_mi->repl_ignore_server_ids, (uchar*) &s_id, i); + if (s_id == ::server_id && replicate_same_server_id) + { + my_error(ER_SLAVE_IGNORE_SERVER_IDS, MYF(0), s_id); + ret= TRUE; + goto err; + } + else + { + if (bsearch((const ulong *) &s_id, + mi->ignore_server_ids.buffer, + mi->ignore_server_ids.elements, sizeof(ulong), + (int (*) (const void*, const void*)) + change_master_server_id_cmp) == NULL) + insert_dynamic(&mi->ignore_server_ids, (uchar*) &s_id); + } + } + sort_dynamic(&mi->ignore_server_ids, (qsort_cmp) change_master_server_id_cmp); + if (lex_mi->ssl != LEX_MASTER_INFO::LEX_MI_UNCHANGED) mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE); @@ -1407,8 +1436,8 @@ bool change_master(THD* thd, Master_info* mi) if (flush_master_info(mi, 0)) { my_error(ER_RELAY_LOG_INIT, MYF(0), "Failed to flush master info file"); - unlock_slave_threads(mi); - DBUG_RETURN(TRUE); + ret= TRUE; + goto err; } if (need_relay_log_purge) { @@ -1419,8 +1448,8 @@ bool change_master(THD* thd, Master_info* mi) &errmsg)) { my_error(ER_RELAY_LOG_FAIL, MYF(0), errmsg); - unlock_slave_threads(mi); - DBUG_RETURN(TRUE); + ret= TRUE; + goto err; } } else @@ -1435,8 +1464,8 @@ bool change_master(THD* thd, Master_info* mi) &msg, 0)) { my_error(ER_RELAY_LOG_INIT, MYF(0), msg); - unlock_slave_threads(mi); - DBUG_RETURN(TRUE); + ret= TRUE; + goto err; } } /* @@ -1473,10 +1502,13 @@ bool change_master(THD* thd, Master_info* mi) pthread_cond_broadcast(&mi->data_cond); pthread_mutex_unlock(&mi->rli.data_lock); +err: unlock_slave_threads(mi); thd_proc_info(thd, 0); - my_ok(thd); - DBUG_RETURN(FALSE); + if (ret == FALSE) + my_ok(thd); + delete_dynamic(&lex_mi->repl_ignore_server_ids); //freeing of parser-time alloc + DBUG_RETURN(ret); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 50395d386e8..7dff91befb0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -740,6 +740,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token IDENT_QUOTED %token IF %token IGNORE_SYM +%token IGNORE_SERVER_IDS_SYM %token IMPORT %token INDEXES %token INDEX_SYM @@ -1559,6 +1560,12 @@ change: LEX *lex = Lex; lex->sql_command = SQLCOM_CHANGE_MASTER; bzero((char*) &lex->mi, sizeof(lex->mi)); + /* + resetting flags that can left from the previous CHANGE MASTER + */ + lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_UNCHANGED; + my_init_dynamic_array(&Lex->mi.repl_ignore_server_ids, + sizeof(::server_id), 16, 16); } master_defs {} @@ -1661,10 +1668,26 @@ master_def: } Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; } + | IGNORE_SERVER_IDS_SYM EQ '(' ignore_server_id_list ')' + { + Lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; + } | master_file_def ; +ignore_server_id_list: + /* Empty */ + | ignore_server_id + | ignore_server_id_list ',' ignore_server_id + ; + +ignore_server_id: + ulong_num + { + insert_dynamic(&Lex->mi.repl_ignore_server_ids, (uchar*) &($1)); + } + master_file_def: MASTER_LOG_FILE_SYM EQ TEXT_STRING_sys { From d9286fbc22ea36348703d8ba5b3f0d6784b4485a Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 12:11:50 +0800 Subject: [PATCH 059/274] Post fix backporting wl#1720 Fix mtr semisync plugin option paths --- mysql-test/mysql-test-run.pl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 434896df6a5..d50195c7d16 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1819,9 +1819,13 @@ sub environment_setup { # Add the path where mysqld will find semisync plugins # -------------------------------------------------------------------------- my $lib_semisync_master_plugin= - mtr_file_exists("$basedir/plugin/semisync/.libs/libsemisync_master.so"); + mtr_file_exists(vs_config_dirs('plugin/semisync',"libsemisync_master.so"), + "$basedir/plugin/semisync/.libs/libsemisync_master.so", + "$basedir/lib/mysql/plugin/libsemisync_master.so"); my $lib_semisync_slave_plugin= - mtr_file_exists("$basedir/plugin/semisync/.libs/libsemisync_slave.so"); + mtr_file_exists(vs_config_dirs('plugin/semisync',"libsemisync_slave.so"), + "$basedir/plugin/semisync/.libs/libsemisync_slave.so", + "$basedir/lib/mysql/plugin/libsemisync_slave.so"); if ($lib_semisync_master_plugin && $lib_semisync_slave_plugin) { $ENV{'SEMISYNC_MASTER_PLUGIN'}= basename($lib_semisync_master_plugin); From ebca60c1ff07ecb57cd2852052534640322ca576 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 13:59:42 +0800 Subject: [PATCH 060/274] Backport BUG#41013 main.bootstrap coredumps in 6.0-rpl When a storage engine failed to initialize before allocated slot number, the slot number would be 0, and when later finalizing this plugin, it would accidentally unplug the storage engine currently uses slot 0. This patch fixed this problem by add a new macro value HA_SLOT_UNDEF to distinguish undefined slot number from slot 0. --- sql/handler.cc | 9 ++++++++- sql/handler.h | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sql/handler.cc b/sql/handler.cc index f966a9099ee..ac959cb62f2 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -413,7 +413,13 @@ int ha_finalize_handlerton(st_plugin_int *plugin) reuse an array slot. Otherwise the number of uninstall/install cycles would be limited. */ - hton2plugin[hton->slot]= NULL; + if (hton->slot != HA_SLOT_UNDEF) + { + /* Make sure we are not unpluging another plugin */ + DBUG_ASSERT(hton2plugin[hton->slot] == plugin); + DBUG_ASSERT(hton->slot < MAX_HA); + hton2plugin[hton->slot]= NULL; + } my_free((uchar*)hton, MYF(0)); @@ -438,6 +444,7 @@ int ha_initialize_handlerton(st_plugin_int *plugin) goto err_no_hton_memory; } + hton->slot= HA_SLOT_UNDEF; /* Historical Requirement */ plugin->data= hton; // shortcut for the future if (plugin->plugin->init && plugin->plugin->init(hton)) diff --git a/sql/handler.h b/sql/handler.h index a281aaa0ad7..ea0b134e53d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -216,6 +216,13 @@ */ #define MAX_HA 15 +/* + Use this instead of 0 as the initial value for the slot number of + handlerton, so that we can distinguish uninitialized slot number + from slot 0. +*/ +#define HA_SLOT_UNDEF ((uint)-1) + /* Parameters for open() (in register form->filestat) HA_GET_INFO does an implicit HA_ABORT_IF_LOCKED From f509a3589653575f1e9dc9f05de11a86be710a68 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 16:07:33 +0800 Subject: [PATCH 061/274] Backport BUG#41613 Slave I/O status inconsistent between SHOW SLAVE STATUS and START SLAVE There are three internal status for slave I/O thread, both MYSQL_SLAVE_RUN_NOT_CONNECT and MYSQL_SLAVE_NOT_RUN are reported as 'No' for Slave_IO_running of command SHOW SLAVE STATUS. Change MYSQL_SLAVE_RUN_NOT_CONNECT to be reported as 'Connecting'. --- sql/slave.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/slave.cc b/sql/slave.cc index 4c13841875c..47842cce225 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1848,7 +1848,8 @@ bool show_master_info(THD* thd, Master_info* mi) protocol->store((ulonglong) mi->rli.group_relay_log_pos); protocol->store(mi->rli.group_master_log_name, &my_charset_bin); protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT ? - "Yes" : "No", &my_charset_bin); + "Yes" : (mi->slave_running == MYSQL_SLAVE_RUN_NOT_CONNECT ? + "Connecting" : "No"), &my_charset_bin); protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin); protocol->store(rpl_filter->get_do_db()); protocol->store(rpl_filter->get_ignore_db()); From bb6953d1d80e5fef2e333e0a4147aa5a43e809ab Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 16:18:40 +0800 Subject: [PATCH 062/274] Backport BUG#38468 Memory leak detected when using mysqlbinlog utility There were two memory leaks in mysqlbinlog command, one was already fixed by previous patches, another one was that defaults_argv was set to the value of argv after parse_args, in which called handle_options after calling load_defaults and changed the value of argv, and caused the memory allocated for defaults arguments not freed. Fixed the problem by setting defaults_argv right after calling load_defaults. --- client/mysqlbinlog.cc | 4 ++-- mysql-test/t/mysqlbinlog.test | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 82af7ca65f6..5713dfa59a1 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1346,7 +1346,6 @@ static int parse_args(int *argc, char*** argv) int ho_error; result_file = stdout; - load_defaults("my",load_default_groups,argc,argv); if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); if (debug_info_flag) @@ -1998,8 +1997,9 @@ int main(int argc, char** argv) my_init_time(); // for time functions + load_defaults("my", load_default_groups, &argc, &argv); + defaults_argv= argv; parse_args(&argc, (char***)&argv); - defaults_argv=argv; if (!argc) { diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 015d4d152cb..04fb5486f31 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -380,3 +380,27 @@ FLUSH LOGS; --echo End of 5.0 tests --echo End of 5.1 tests + +# +# BUG#38468 Memory leak detected when using mysqlbinlog utility; +# +disable_query_log; +RESET MASTER; +CREATE TABLE t1 SELECT 1; +FLUSH LOGS; +DROP TABLE t1; +enable_query_log; + +# Write an empty file for comparison +write_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.warn.empty; +EOF + +# Before fix of BUG#38468, this would generate some warnings +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 >/dev/null 2> $MYSQLTEST_VARDIR/tmp/mysqlbinlog.warn + +# Make sure the command above does not generate any error or warnings +diff_files $MYSQLTEST_VARDIR/tmp/mysqlbinlog.warn $MYSQLTEST_VARDIR/tmp/mysqlbinlog.warn.empty; + +# Cleanup for this part of test +remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.warn.empty; +remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.warn; From 9739efbfec4c069996cf2f46f165e555a7edf30f Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 16:25:53 +0800 Subject: [PATCH 063/274] Backport BUG#25192 Using relay-log and relay-log-index without values produces unexpected results. Options loaded from config files were added before command line arguments, and they were parsed together, which could interprete the following: option-a option-b as --option-a=--option-b if 'option-a' requires a value, and caused confusing. Because all options that requires a value are always given in the form '--option=value', so it's an error if there is no '=value' part for such an option read from config file. This patch added a separator to separate the arguments from config files and that from command line, so that they can be handled differently. And report an error for options loaded from config files that requires a value and is not given in the form '--option=value'. --- extra/my_print_defaults.c | 3 +- include/my_sys.h | 1 + mysys/default.c | 49 +++++++++++++++++++++++------ mysys/my_getopt.c | 33 +++++++++++++++++-- sql-common/client.c | 2 ++ storage/ndb/test/run-test/setup.cpp | 8 +++++ 6 files changed, 83 insertions(+), 13 deletions(-) diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c index 06f7e51c380..42a5cbd6877 100644 --- a/extra/my_print_defaults.c +++ b/extra/my_print_defaults.c @@ -192,7 +192,8 @@ int main(int argc, char **argv) } for (argument= arguments+1 ; *argument ; argument++) - puts(*argument); + if (*argument != args_separator) /* skip arguments separator */ + puts(*argument); my_free((char*) load_default_groups,MYF(0)); free_defaults(arguments); diff --git a/include/my_sys.h b/include/my_sys.h index 222564e0b44..4e85525e4b0 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -843,6 +843,7 @@ extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len); extern int get_defaults_options(int argc, char **argv, char **defaults, char **extra_defaults, char **group_suffix); +extern const char *args_separator; extern int my_load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv, const char ***); extern int load_defaults(const char *conf_file, const char **groups, diff --git a/mysys/default.c b/mysys/default.c index 1c021b4584f..c610b57c6d1 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -41,6 +41,29 @@ #include #endif +/** + arguments separator + + load_defaults() loads arguments from config file and put them + before the arguments from command line, this separator is used to + separate the arguments loaded from config file and arguments user + provided on command line. + + Options with value loaded from config file are always in the form + '--option=value', while for command line options, the value can be + given as the next argument. Thus we used a separator so that + handle_options() can distinguish them. + + Note: any other places that does not need to distinguish them + should skip the separator. + + The content of arguments separator does not matter, one should only + check the pointer, use "----args-separator----" here to ease debug + if someone misused it. + + See BUG#25192 +*/ +const char *args_separator= "----args-separator----"; const char *my_defaults_file=0; const char *my_defaults_group_suffix=0; char *my_defaults_extra_file=0; @@ -454,10 +477,11 @@ int my_load_defaults(const char *conf_file, const char **groups, goto err; res= (char**) (ptr+sizeof(alloc)); res[0]= **argv; /* Copy program name */ + /* set arguments separator */ + res[1]= args_separator; for (i=2 ; i < (uint) *argc ; i++) - res[i-1]=argv[0][i]; - res[i-1]=0; /* End pointer */ - (*argc)--; + res[i]=argv[0][i]; + res[i]=0; /* End pointer */ *argv=res; *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */ if (default_directories) @@ -487,7 +511,7 @@ int my_load_defaults(const char *conf_file, const char **groups, or a forced default file */ if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+ - (args.elements + *argc +1) *sizeof(char*)))) + (args.elements + *argc + 1 + 1) *sizeof(char*)))) goto err; res= (char**) (ptr+sizeof(alloc)); @@ -508,12 +532,16 @@ int my_load_defaults(const char *conf_file, const char **groups, --*argc; ++*argv; /* skip argument */ } - if (*argc) - memcpy((uchar*) (res+1+args.elements), (char*) ((*argv)+1), - (*argc-1)*sizeof(char*)); - res[args.elements+ *argc]=0; /* last null */ + /* set arguments separator for arguments from config file and + command line */ + res[args.elements+1]= args_separator; - (*argc)+=args.elements; + if (*argc) + memcpy((uchar*) (res+1+args.elements+1), (char*) ((*argv)+1), + (*argc-1)*sizeof(char*)); + res[args.elements+ *argc+1]=0; /* last null */ + + (*argc)+=args.elements+1; *argv= (char**) res; *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */ delete_dynamic(&args); @@ -523,7 +551,8 @@ int my_load_defaults(const char *conf_file, const char **groups, printf("%s would have been started with the following arguments:\n", **argv); for (i=1 ; i < *argc ; i++) - printf("%s ", (*argv)[i]); + if ((*argv)[i] != args_separator) /* skip arguments separator */ + printf("%s ", (*argv)[i]); puts(""); exit(0); } diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index b6eb6dac54f..22b1216f99c 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -121,6 +121,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *optp; uchar* *value; int error, i; + my_bool is_cmdline_arg= 1; LINT_INIT(opt_found); /* handle_options() assumes arg0 (program name) always exists */ @@ -130,10 +131,34 @@ int handle_options(int *argc, char ***argv, (*argv)++; /* --- || ---- */ init_variables(longopts, init_one_value); + /* + Search for args_separator, if found, then the first part of the + arguments are loaded from configs + */ + for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) + { + if (*pos == args_separator) + { + is_cmdline_arg= 0; + break; + } + } + for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) { char **first= pos; char *cur_arg= *pos; + if (!is_cmdline_arg && (cur_arg == args_separator)) + { + is_cmdline_arg= 1; + + /* save the separator too if skip unkown options */ + if (my_getopt_skip_unknown) + (*argv)[argvpos++]= cur_arg; + else + (*argc)--; + continue; + } if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */ { char *argument= 0; @@ -426,8 +451,12 @@ invalid value '%s'", } else if (optp->arg_type == REQUIRED_ARG && !optend) { - /* Check if there are more arguments after this one */ - if (!*++pos) + /* Check if there are more arguments after this one, + + Note: options loaded from config file that requires value + should always be in the form '--option=value'. + */ + if (!is_cmdline_arg || !*++pos) { if (my_getopt_print_errors) my_getopt_error_reporter(ERROR_LEVEL, diff --git a/sql-common/client.c b/sql-common/client.c index 84029b449af..cbed3a5e2a8 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1053,6 +1053,8 @@ void mysql_read_default_options(struct st_mysql_options *options, char **option=argv; while (*++option) { + if (option[0] == args_separator) /* skip arguments separator */ + continue; /* DBUG_PRINT("info",("option: %s",option[0])); */ if (option[0][0] == '-' && option[0][1] == '-') { diff --git a/storage/ndb/test/run-test/setup.cpp b/storage/ndb/test/run-test/setup.cpp index cbb7a34f171..60f8285888c 100644 --- a/storage/ndb/test/run-test/setup.cpp +++ b/storage/ndb/test/run-test/setup.cpp @@ -105,6 +105,8 @@ setup_config(atrt_config& config) */ for (j = 0; j<(size_t)argc; j++) { + if (tmp[j] == args_separator) /* skip arguments separator */ + continue; for (k = 0; proc_args[k].name; k++) { if (!strncmp(tmp[j], proc_args[k].name, strlen(proc_args[k].name))) @@ -369,6 +371,12 @@ load_options(int argc, char** argv, int type, atrt_options& opts) { for (size_t i = 0; i<(size_t)argc; i++) { + /** + * Skip the separator for arguments from config file and command + * line + */ + if (argv[i] == args_separator) + continue; for (size_t j = 0; f_options[j].name; j++) { const char * name = f_options[j].name; From 228ae2bf50c776e94decc731decefe6eaae0118f Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 16:35:03 +0800 Subject: [PATCH 064/274] Backport BUG#12190 CHANGE MASTER has differ path requiremts on MASTER_LOG_FILE and RELAY_LOG_FILE CHANGE MASTER TO command required the value for RELAY_LOG_FILE to be an absolute path, which was different from the requirement of MASTER_LOG_FILE. This patch fixed the problem by changing the value for RELAY_LOG_FILE to be the basename of the log file as that for MASTER_LOG_FILE. --- mysql-test/include/setup_fake_relay_log.inc | 2 +- .../t/binlog_auto_increment_bug33029.test | 2 +- .../suite/rpl/r/rpl_change_master.result | 17 ++++++ mysql-test/suite/rpl/t/rpl_change_master.test | 53 +++++++++++++++++++ sql/sql_repl.cc | 6 ++- 5 files changed, 76 insertions(+), 4 deletions(-) diff --git a/mysql-test/include/setup_fake_relay_log.inc b/mysql-test/include/setup_fake_relay_log.inc index f88806e1079..b3df7abba76 100644 --- a/mysql-test/include/setup_fake_relay_log.inc +++ b/mysql-test/include/setup_fake_relay_log.inc @@ -69,7 +69,7 @@ let $_fake_relay_log_purge= `SELECT @@global.relay_log_purge`; # Create relay log file. copy_file $fake_relay_log $_fake_relay_log; # Create relay log index. ---exec echo $_fake_filename-fake.000001 > $_fake_relay_index +--exec echo ./$_fake_filename-fake.000001 > $_fake_relay_index # Setup replication from existing relay log. eval CHANGE MASTER TO MASTER_HOST='dummy.localdomain', RELAY_LOG_FILE='$_fake_filename-fake.000001', RELAY_LOG_POS=4; diff --git a/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test b/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test index 5297767675c..1277f6e7ccb 100644 --- a/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test +++ b/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test @@ -26,7 +26,7 @@ let $MYSQLD_DATADIR= `select @@datadir`; copy_file $MYSQL_TEST_DIR/std_data/bug33029-slave-relay-bin.000001 $MYSQLD_DATADIR/slave-relay-bin.000001; write_file $MYSQLD_DATADIR/slave-relay-bin.index; -slave-relay-bin.000001 +./slave-relay-bin.000001 EOF change master to diff --git a/mysql-test/suite/rpl/r/rpl_change_master.result b/mysql-test/suite/rpl/r/rpl_change_master.result index 7bc5473c46e..a51ba50475b 100644 --- a/mysql-test/suite/rpl/r/rpl_change_master.result +++ b/mysql-test/suite/rpl/r/rpl_change_master.result @@ -100,3 +100,20 @@ n 1 2 drop table t1; +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +create table t1 (a int); +insert into t1 values (1); +flush logs; +insert into t1 values (2); +include/stop_slave.inc +delete from t1 where a=2; +CHANGE MASTER TO relay_log_file='slave-relay-bin.000005', relay_log_pos=4; +start slave sql_thread; +start slave io_thread; +set global relay_log_purge=1; +drop table t1; diff --git a/mysql-test/suite/rpl/t/rpl_change_master.test b/mysql-test/suite/rpl/t/rpl_change_master.test index d0cd40e2e11..c1ef417ea78 100644 --- a/mysql-test/suite/rpl/t/rpl_change_master.test +++ b/mysql-test/suite/rpl/t/rpl_change_master.test @@ -33,3 +33,56 @@ connection slave; sync_with_master; # End of 4.1 tests + +# +# BUG#12190 CHANGE MASTER has differ path requiremts on MASTER_LOG_FILE and RELAY_LOG_FILE +# + +source include/master-slave-reset.inc; + +connection master; +create table t1 (a int); +insert into t1 values (1); +flush logs; +insert into t1 values (2); + +# Note: the master positon saved by this will also be used by the +# 'sync_with_master' below. +sync_slave_with_master; + +# Check if the table t1 and t2 are identical on master and slave; +let $diff_table_1= master:test.t1 +let $diff_table_2= slave:test.t1 +source include/diff_tables.inc; + +connection slave; +source include/stop_slave.inc; +delete from t1 where a=2; + +# start replication from the second insert, after fix of BUG#12190, +# relay_log_file does not use absolute path, only the filename is +# required +# +# Note: the follow change master will automatically reset +# relay_log_purge to false, save the old value to restore +let $relay_log_purge= `select @@global.relay_log_purge`; +CHANGE MASTER TO relay_log_file='slave-relay-bin.000005', relay_log_pos=4; +start slave sql_thread; +source include/wait_for_slave_sql_to_start.inc; + +# Sync to the same position saved by the 'sync_slave_with_master' above. +sync_with_master; + +# Check if the table t1 and t2 are identical on master and slave; +let $diff_table_1= master:test.t1 +let $diff_table_2= slave:test.t1 +source include/diff_tables.inc; + +# clean up +connection slave; +start slave io_thread; +source include/wait_for_slave_io_to_start.inc; +eval set global relay_log_purge=$relay_log_purge; +connection master; +drop table t1; +sync_slave_with_master; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index a899c8b7551..2c373059bf7 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1400,9 +1400,11 @@ bool change_master(THD* thd, Master_info* mi) if (lex_mi->relay_log_name) { need_relay_log_purge= 0; - strmake(mi->rli.group_relay_log_name,lex_mi->relay_log_name, + char relay_log_name[FN_REFLEN]; + mi->rli.relay_log.make_log_name(relay_log_name, lex_mi->relay_log_name); + strmake(mi->rli.group_relay_log_name, relay_log_name, sizeof(mi->rli.group_relay_log_name)-1); - strmake(mi->rli.event_relay_log_name,lex_mi->relay_log_name, + strmake(mi->rli.event_relay_log_name, relay_log_name, sizeof(mi->rli.event_relay_log_name)-1); } From 4381f7ed90f54be0be0c569e38d17aefe98b7d0b Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 16:40:06 +0800 Subject: [PATCH 065/274] Backport post fix compiler warnings and test failures for BUG#25192 BUG#12190 --- mysql-test/include/setup_fake_relay_log.inc | 16 +++++++++++++++- .../t/binlog_auto_increment_bug33029.test | 19 ++++++++++++++++--- mysys/default.c | 4 ++-- sql/log.cc | 2 +- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/mysql-test/include/setup_fake_relay_log.inc b/mysql-test/include/setup_fake_relay_log.inc index b3df7abba76..b11e6afbeca 100644 --- a/mysql-test/include/setup_fake_relay_log.inc +++ b/mysql-test/include/setup_fake_relay_log.inc @@ -69,7 +69,21 @@ let $_fake_relay_log_purge= `SELECT @@global.relay_log_purge`; # Create relay log file. copy_file $fake_relay_log $_fake_relay_log; # Create relay log index. ---exec echo ./$_fake_filename-fake.000001 > $_fake_relay_index + +# After patch for BUG#12190, the filename used in CHANGE MASTER +# RELAY_LOG_FILE will be automatically added the directory of the +# relay log before comparison, thus we need to added the directory +# part (./ on unix .\ on windows) when faking the relay-log-bin.index. + +if (`select convert(@@version_compile_os using latin1) IN ("Win32","Win64","Windows") = 0`) +{ + eval select './$_fake_filename-fake.000001\n' into dumpfile '$_fake_relay_index'; +} + +if (`select convert(@@version_compile_os using latin1) IN ("Win32","Win64","Windows") != 0`) +{ + eval select '.\\\\$_fake_filename-fake.000001\n' into dumpfile '$_fake_relay_index'; +} # Setup replication from existing relay log. eval CHANGE MASTER TO MASTER_HOST='dummy.localdomain', RELAY_LOG_FILE='$_fake_filename-fake.000001', RELAY_LOG_POS=4; diff --git a/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test b/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test index 1277f6e7ccb..19137066429 100644 --- a/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test +++ b/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test @@ -25,9 +25,22 @@ let $MYSQLD_DATADIR= `select @@datadir`; copy_file $MYSQL_TEST_DIR/std_data/bug33029-slave-relay-bin.000001 $MYSQLD_DATADIR/slave-relay-bin.000001; -write_file $MYSQLD_DATADIR/slave-relay-bin.index; -./slave-relay-bin.000001 -EOF + +# After patch for BUG#12190, the filename used in CHANGE MASTER +# RELAY_LOG_FILE will be automatically added the directory of the +# relay log before comparison, thus we need to added the directory +# part (./ on unix .\ on windows) when faking the relay-log-bin.index. +disable_query_log; +if (`select convert(@@version_compile_os using latin1) IN ("Win32","Win64","Windows") = 0`) +{ + eval select './slave-relay-bin.000001\n' into dumpfile '$MYSQLD_DATADIR/slave-relay-bin.index'; +} + +if (`select convert(@@version_compile_os using latin1) IN ("Win32","Win64","Windows") != 0`) +{ + eval select '.\\\\slave-relay-bin.000001\n' into dumpfile '$MYSQLD_DATADIR/slave-relay-bin.index'; +} +enable_query_log; change master to MASTER_HOST='dummy.localdomain', diff --git a/mysys/default.c b/mysys/default.c index c610b57c6d1..6468cf2b35d 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -478,7 +478,7 @@ int my_load_defaults(const char *conf_file, const char **groups, res= (char**) (ptr+sizeof(alloc)); res[0]= **argv; /* Copy program name */ /* set arguments separator */ - res[1]= args_separator; + res[1]= (char *)args_separator; for (i=2 ; i < (uint) *argc ; i++) res[i]=argv[0][i]; res[i]=0; /* End pointer */ @@ -534,7 +534,7 @@ int my_load_defaults(const char *conf_file, const char **groups, /* set arguments separator for arguments from config file and command line */ - res[args.elements+1]= args_separator; + res[args.elements+1]= (char *)args_separator; if (*argc) memcpy((uchar*) (res+1+args.elements+1), (char*) ((*argv)+1), diff --git a/sql/log.cc b/sql/log.cc index 16f54649d2d..a523c111e87 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1901,7 +1901,7 @@ updating the index files.", max_found); */ if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN)) { - sql_print_error("Log filename too large: %s%s (%d). \ + sql_print_error("Log filename too large: %s%s (%lu). \ Please fix this by archiving old logs and updating the \ index files.", name, ext_buf, (strlen(ext_buf) + (end - name))); error= 1; From dfbac1dd1dea74ad281f1bcfc98dc107a8180192 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 16:50:05 +0800 Subject: [PATCH 066/274] Backport BUG#34227 Replication permission error message is misleading According to Jon's comment, add (at least one of) to the error message. --- mysql-test/r/mysqldump.result | 8 ++++---- sql/share/errmsg.txt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 8162e1aca05..b2a4c1ae585 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -3554,11 +3554,11 @@ use test; create user mysqltest_1@localhost; create table t1(a int, b varchar(34)); reset master; -mysqldump: Couldn't execute 'FLUSH /*!40101 LOCAL */ TABLES': Access denied; you need the RELOAD privilege for this operation (1227) -mysqldump: Couldn't execute 'FLUSH /*!40101 LOCAL */ TABLES': Access denied; you need the RELOAD privilege for this operation (1227) +mysqldump: Couldn't execute 'FLUSH /*!40101 LOCAL */ TABLES': Access denied; you need (at least one of) the RELOAD privilege(s) for this operation (1227) +mysqldump: Couldn't execute 'FLUSH /*!40101 LOCAL */ TABLES': Access denied; you need (at least one of) the RELOAD privilege(s) for this operation (1227) grant RELOAD on *.* to mysqltest_1@localhost; -mysqldump: Couldn't execute 'SHOW MASTER STATUS': Access denied; you need the SUPER,REPLICATION CLIENT privilege for this operation (1227) -mysqldump: Couldn't execute 'SHOW MASTER STATUS': Access denied; you need the SUPER,REPLICATION CLIENT privilege for this operation (1227) +mysqldump: Couldn't execute 'SHOW MASTER STATUS': Access denied; you need (at least one of) the SUPER,REPLICATION CLIENT privilege(s) for this operation (1227) +mysqldump: Couldn't execute 'SHOW MASTER STATUS': Access denied; you need (at least one of) the SUPER,REPLICATION CLIENT privilege(s) for this operation (1227) grant REPLICATION CLIENT on *.* to mysqltest_1@localhost; drop table t1; drop user mysqltest_1@localhost; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 18d3a41424a..1773599c63d 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -4620,7 +4620,7 @@ ER_USER_LIMIT_REACHED 42000 swe "Användare '%-.64s' har överskridit '%s' (nuvarande värde: %ld)" ER_SPECIFIC_ACCESS_DENIED_ERROR 42000 nla "Toegang geweigerd. U moet het %-.128s privilege hebben voor deze operatie" - eng "Access denied; you need the %-.128s privilege for this operation" + eng "Access denied; you need (at least one of) the %-.128s privilege(s) for this operation" ger "Kein Zugriff. Hierfür wird die Berechtigung %-.128s benötigt" ita "Accesso non consentito. Serve il privilegio %-.128s per questa operazione" por "Acesso negado. Você precisa o privilégio %-.128s para essa operação" From 280bf1cee6e0dd5ee5dbc97e9f3efffb16e5617d Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 17:12:10 +0800 Subject: [PATCH 067/274] Backport Post fix of result files after push of BUG#34227 --- mysql-test/r/events_bugs.result | 4 ++-- mysql-test/r/grant2.result | 4 ++-- mysql-test/r/information_schema_db.result | 2 +- mysql-test/r/sp-security.result | 4 ++-- mysql-test/r/trigger_notembedded.result | 4 ++-- mysql-test/r/view_grant.result | 12 ++++++------ mysql-test/suite/binlog/r/binlog_grant.result | 6 +++--- mysql-test/suite/federated/federated_server.result | 8 ++++---- mysql-test/suite/funcs_1/r/innodb_trig_03e.result | 4 ++-- mysql-test/suite/funcs_1/r/memory_trig_03e.result | 4 ++-- mysql-test/suite/funcs_1/r/myisam_trig_03e.result | 4 ++-- mysql-test/suite/funcs_1/r/ndb_trig_03e.result | 4 ++-- mysql-test/suite/rpl/r/rpl_temporary.result | 4 ++-- mysql-test/suite/sys_vars/r/read_only_func.result | 2 +- 14 files changed, 33 insertions(+), 33 deletions(-) diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result index 50bfa97c59f..15a9e226c39 100644 --- a/mysql-test/r/events_bugs.result +++ b/mysql-test/r/events_bugs.result @@ -375,7 +375,7 @@ SELECT event_name, definer FROM INFORMATION_SCHEMA.EVENTS; event_name definer e1 mysqltest_u1@localhost ALTER DEFINER=root@localhost EVENT e1 ON SCHEDULE EVERY 1 HOUR; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation SELECT event_name, definer FROM INFORMATION_SCHEMA.EVENTS; event_name definer e1 mysqltest_u1@localhost @@ -386,7 +386,7 @@ event_name definer e1 mysqltest_u1@localhost DROP EVENT e1; CREATE DEFINER=root@localhost EVENT e1 ON SCHEDULE EVERY 1 DAY DO SELECT 1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation DROP EVENT e1; ERROR HY000: Unknown event 'e1' DROP USER mysqltest_u1@localhost; diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 7c2023127f0..461ad78bbb6 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -121,9 +121,9 @@ mysqltest_5@host5, mysqltest_6@host6, mysqltest_7@host7; create database mysqltest_1; grant select, insert, update on `mysqltest\_1`.* to mysqltest_1@localhost; set sql_log_off = 1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation set sql_log_bin = 0; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation delete from mysql.user where user like 'mysqltest\_1'; delete from mysql.db where user like 'mysqltest\_1'; drop database mysqltest_1; diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 6305f8cd47a..4cc96d3e9ce 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -121,7 +121,7 @@ grant insert on v1 to testdb_2@localhost; create view v5 as select f1 from t1; grant show view on v5 to testdb_2@localhost; create definer=`no_such_user`@`no_such_host` view v6 as select f1 from t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation use testdb_1; create view v6 as select f1 from t1; grant show view on v6 to testdb_2@localhost; diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index 65c94577a57..ecac8fed8c4 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -349,9 +349,9 @@ CREATE FUNCTION wl2897_f1() RETURNS INT RETURN 1; ---> connection: mysqltest_1_con USE mysqltest; CREATE DEFINER=root@localhost PROCEDURE wl2897_p2() SELECT 2; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation CREATE DEFINER=root@localhost FUNCTION wl2897_f2() RETURNS INT RETURN 2; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation ---> connection: mysqltest_2_con use mysqltest; diff --git a/mysql-test/r/trigger_notembedded.result b/mysql-test/r/trigger_notembedded.result index 335e6910a3a..f8975cb2ee5 100644 --- a/mysql-test/r/trigger_notembedded.result +++ b/mysql-test/r/trigger_notembedded.result @@ -117,7 +117,7 @@ CREATE DEFINER='mysqltest_inv'@'localhost' TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @new_sum = 0; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation ---> connection: default use mysqltest_db1; @@ -473,7 +473,7 @@ SELECT trigger_name FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'db1'; trigger_name SHOW CREATE TRIGGER db1.trg; -ERROR 42000: Access denied; you need the TRIGGER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the TRIGGER privilege(s) for this operation DROP USER 'no_rights'@'localhost'; DROP DATABASE db1; End of 5.1 tests. diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 7e280fa2fe5..982b3b98d9c 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -16,7 +16,7 @@ create table mysqltest.t2 (a int, b int); grant select on mysqltest.t1 to mysqltest_1@localhost; grant create view,select on test.* to mysqltest_1@localhost; create definer=root@localhost view v1 as select * from mysqltest.t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation create view v1 as select * from mysqltest.t1; alter view v1 as select * from mysqltest.t1; ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 'v1' @@ -779,11 +779,11 @@ GRANT CREATE VIEW ON db26813.v2 TO u26813@localhost; GRANT DROP, CREATE VIEW ON db26813.v3 TO u26813@localhost; GRANT SELECT ON db26813.t1 TO u26813@localhost; ALTER VIEW v1 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation ALTER VIEW v2 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation ALTER VIEW v3 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation SHOW CREATE VIEW v3; View Create View character_set_client collation_connection v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci @@ -807,9 +807,9 @@ GRANT DROP, CREATE VIEW ON mysqltest_29908.v1 TO u29908_2@localhost; GRANT DROP, CREATE VIEW, SHOW VIEW ON mysqltest_29908.v2 TO u29908_2@localhost; GRANT SELECT ON mysqltest_29908.t1 TO u29908_2@localhost; ALTER VIEW v1 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation ALTER VIEW v2 AS SELECT f2 FROM t1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation SHOW CREATE VIEW v2; View Create View character_set_client collation_connection v2 CREATE ALGORITHM=UNDEFINED DEFINER=`u29908_1`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci diff --git a/mysql-test/suite/binlog/r/binlog_grant.result b/mysql-test/suite/binlog/r/binlog_grant.result index 21ebb891103..548013fcbf2 100644 --- a/mysql-test/suite/binlog/r/binlog_grant.result +++ b/mysql-test/suite/binlog/r/binlog_grant.result @@ -13,16 +13,16 @@ set session sql_log_bin = 1; set global sql_log_bin = 1; ERROR HY000: Variable 'sql_log_bin' is a SESSION variable and can't be used with SET GLOBAL set session sql_log_bin = 1; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation **** Variable BINLOG_FORMAT **** [root] set global binlog_format = row; set session binlog_format = row; [plain] set global binlog_format = row; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation set session binlog_format = row; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation **** Clean up **** set global binlog_format = @saved_binlog_format; drop user mysqltest_1@localhost; diff --git a/mysql-test/suite/federated/federated_server.result b/mysql-test/suite/federated/federated_server.result index 2c20d1c1d57..5079a4dcfa0 100644 --- a/mysql-test/suite/federated/federated_server.result +++ b/mysql-test/suite/federated/federated_server.result @@ -197,13 +197,13 @@ select * from federated.t1; id name 1 this is legitimate alter server s1 options (database 'db_bogus'); -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation flush tables; select * from federated.t1; id name 1 this is legitimate alter server s1 options (database 'db_bogus'); -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation flush tables; select * from federated.t1; id name @@ -214,7 +214,7 @@ select * from federated.t1; id name 2 this is bogus drop server if exists 's1'; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation create server 's1' foreign data wrapper 'mysql' options (HOST '127.0.0.1', DATABASE 'db_legitimate', @@ -223,7 +223,7 @@ PASSWORD '', PORT SLAVE_PORT, SOCKET '', OWNER 'root'); -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation drop server 's1'; create server 's1' foreign data wrapper 'mysql' options (HOST '127.0.0.1', diff --git a/mysql-test/suite/funcs_1/r/innodb_trig_03e.result b/mysql-test/suite/funcs_1/r/innodb_trig_03e.result index 476ccc6ebd8..25edc0f68bb 100644 --- a/mysql-test/suite/funcs_1/r/innodb_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/innodb_trig_03e.result @@ -1251,7 +1251,7 @@ drop trigger trg1_0; create definer=not_ex_user@localhost trigger trg1_0 before INSERT on t1 for each row set new.f1 = 'trig 1_0-yes'; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation create definer=current_user trigger trg1_1 before INSERT on t1 for each row set new.f1 = 'trig 1_1-yes'; @@ -1284,7 +1284,7 @@ GRANT SELECT, INSERT, UPDATE, TRIGGER ON `priv_db`.`t1` TO 'test_yesprivs'@'loca create definer=not_ex_user@localhost trigger trg1_3 after UPDATE on t1 for each row set @var1 = 'trig 1_3-yes'; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation select current_user; current_user root@localhost diff --git a/mysql-test/suite/funcs_1/r/memory_trig_03e.result b/mysql-test/suite/funcs_1/r/memory_trig_03e.result index bbee7d47e7e..462a8858029 100644 --- a/mysql-test/suite/funcs_1/r/memory_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/memory_trig_03e.result @@ -1252,7 +1252,7 @@ drop trigger trg1_0; create definer=not_ex_user@localhost trigger trg1_0 before INSERT on t1 for each row set new.f1 = 'trig 1_0-yes'; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation create definer=current_user trigger trg1_1 before INSERT on t1 for each row set new.f1 = 'trig 1_1-yes'; @@ -1285,7 +1285,7 @@ GRANT SELECT, INSERT, UPDATE, TRIGGER ON `priv_db`.`t1` TO 'test_yesprivs'@'loca create definer=not_ex_user@localhost trigger trg1_3 after UPDATE on t1 for each row set @var1 = 'trig 1_3-yes'; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation select current_user; current_user root@localhost diff --git a/mysql-test/suite/funcs_1/r/myisam_trig_03e.result b/mysql-test/suite/funcs_1/r/myisam_trig_03e.result index e4dc67098ad..104db478638 100644 --- a/mysql-test/suite/funcs_1/r/myisam_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/myisam_trig_03e.result @@ -1252,7 +1252,7 @@ drop trigger trg1_0; create definer=not_ex_user@localhost trigger trg1_0 before INSERT on t1 for each row set new.f1 = 'trig 1_0-yes'; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation create definer=current_user trigger trg1_1 before INSERT on t1 for each row set new.f1 = 'trig 1_1-yes'; @@ -1285,7 +1285,7 @@ GRANT SELECT, INSERT, UPDATE, TRIGGER ON `priv_db`.`t1` TO 'test_yesprivs'@'loca create definer=not_ex_user@localhost trigger trg1_3 after UPDATE on t1 for each row set @var1 = 'trig 1_3-yes'; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation select current_user; current_user root@localhost diff --git a/mysql-test/suite/funcs_1/r/ndb_trig_03e.result b/mysql-test/suite/funcs_1/r/ndb_trig_03e.result index 84260822edf..73388680481 100644 --- a/mysql-test/suite/funcs_1/r/ndb_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/ndb_trig_03e.result @@ -1251,7 +1251,7 @@ drop trigger trg1_0; create definer=not_ex_user@localhost trigger trg1_0 before INSERT on t1 for each row set new.f1 = 'trig 1_0-yes'; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation create definer=current_user trigger trg1_1 before INSERT on t1 for each row set new.f1 = 'trig 1_1-yes'; @@ -1284,7 +1284,7 @@ GRANT SELECT, INSERT, UPDATE, TRIGGER ON `priv_db`.`t1` TO 'test_yesprivs'@'loca create definer=not_ex_user@localhost trigger trg1_3 after UPDATE on t1 for each row set @var1 = 'trig 1_3-yes'; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation select current_user; current_user root@localhost diff --git a/mysql-test/suite/rpl/r/rpl_temporary.result b/mysql-test/suite/rpl/r/rpl_temporary.result index 631eb0677b0..b2400a03f63 100644 --- a/mysql-test/suite/rpl/r/rpl_temporary.result +++ b/mysql-test/suite/rpl/r/rpl_temporary.result @@ -27,12 +27,12 @@ Warning 1265 Data truncated for column 'b' at row 1 DROP TABLE t1; SET @save_select_limit=@@session.sql_select_limit; SET @@session.sql_select_limit=10, @@session.pseudo_thread_id=100; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation SELECT @@session.sql_select_limit = @save_select_limit; @@session.sql_select_limit = @save_select_limit 1 SET @@session.sql_select_limit=10, @@session.sql_log_bin=0; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation SELECT @@session.sql_select_limit = @save_select_limit; @@session.sql_select_limit = @save_select_limit 1 diff --git a/mysql-test/suite/sys_vars/r/read_only_func.result b/mysql-test/suite/sys_vars/r/read_only_func.result index 35b42d468d6..7e98b7adc50 100644 --- a/mysql-test/suite/sys_vars/r/read_only_func.result +++ b/mysql-test/suite/sys_vars/r/read_only_func.result @@ -20,7 +20,7 @@ id name CREATE user sameea; ** Connecting connn using username 'sameea' ** SET Global read_ONLY=ON; -ERROR 42000: Access denied; you need the SUPER privilege for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation CREATE TABLE t2 ( id INT NOT NULL auto_increment, From 54120363efb9653a8a88a00062e6ef5234ffaf41 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 17:24:21 +0800 Subject: [PATCH 068/274] Backport fixes for the follow tests binlog_tmp_table rpl_row_sp006_InnoDB rpl_slave_status --- mysql-test/extra/rpl_tests/rpl_row_sp006.test | 3 ++- mysql-test/suite/binlog/r/binlog_tmp_table.result | 1 + mysql-test/suite/binlog/t/binlog_tmp_table.test | 2 ++ mysql-test/suite/rpl/r/rpl_row_sp006_InnoDB.result | 3 ++- mysql-test/suite/rpl/t/rpl_slave_status.test | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_row_sp006.test b/mysql-test/extra/rpl_tests/rpl_row_sp006.test index 897d7e492bf..613ce630f90 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_sp006.test +++ b/mysql-test/extra/rpl_tests/rpl_row_sp006.test @@ -11,7 +11,8 @@ # Begin clean up test section connection master; --disable_warnings -create database if not exists mysqltest1; +drop database if exists mysqltest1; +create database mysqltest1; DROP PROCEDURE IF EXISTS mysqltest1.p1; DROP PROCEDURE IF EXISTS mysqltest1.p2; DROP TABLE IF EXISTS mysqltest1.t2; diff --git a/mysql-test/suite/binlog/r/binlog_tmp_table.result b/mysql-test/suite/binlog/r/binlog_tmp_table.result index e4928432324..b057d24cba9 100644 --- a/mysql-test/suite/binlog/r/binlog_tmp_table.result +++ b/mysql-test/suite/binlog/r/binlog_tmp_table.result @@ -1,3 +1,4 @@ +reset master; create table foo (a int); flush logs; create temporary table tmp1_foo like foo; diff --git a/mysql-test/suite/binlog/t/binlog_tmp_table.test b/mysql-test/suite/binlog/t/binlog_tmp_table.test index 6947959a5e0..cd147149ed1 100644 --- a/mysql-test/suite/binlog/t/binlog_tmp_table.test +++ b/mysql-test/suite/binlog/t/binlog_tmp_table.test @@ -31,6 +31,8 @@ source include/have_binlog_format_mixed_or_statement.inc; connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,); connect (master1,127.0.0.1,root,,test,$MASTER_MYPORT,); +reset master; + create table foo (a int); flush logs; diff --git a/mysql-test/suite/rpl/r/rpl_row_sp006_InnoDB.result b/mysql-test/suite/rpl/r/rpl_row_sp006_InnoDB.result index 8339e77d3a0..0f4dd71f389 100644 --- a/mysql-test/suite/rpl/r/rpl_row_sp006_InnoDB.result +++ b/mysql-test/suite/rpl/r/rpl_row_sp006_InnoDB.result @@ -4,7 +4,8 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -create database if not exists mysqltest1; +drop database if exists mysqltest1; +create database mysqltest1; DROP PROCEDURE IF EXISTS mysqltest1.p1; DROP PROCEDURE IF EXISTS mysqltest1.p2; DROP TABLE IF EXISTS mysqltest1.t2; diff --git a/mysql-test/suite/rpl/t/rpl_slave_status.test b/mysql-test/suite/rpl/t/rpl_slave_status.test index 4edf1802a5d..02fd555d13c 100644 --- a/mysql-test/suite/rpl/t/rpl_slave_status.test +++ b/mysql-test/suite/rpl/t/rpl_slave_status.test @@ -54,6 +54,7 @@ sync_slave_with_master; source include/stop_slave.inc; START SLAVE; source include/wait_for_slave_sql_to_start.inc; +source include/wait_for_slave_io_to_stop.inc; --echo ==== Verify that Slave_IO_Running = No ==== let $result= query_get_value("SHOW SLAVE STATUS", Slave_IO_Running, 1); From f1437d6afdc53fce49867781b14675003b4a32c3 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 2 Oct 2009 11:31:05 +0200 Subject: [PATCH 069/274] BUG#47754, used number of parts instead of number of list values as end part for list partitioning in column list partitioning --- mysql-test/r/partition_column.result | 9 +++++++++ mysql-test/t/partition_column.test | 5 +++++ sql/sql_partition.cc | 10 +++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 66308321a95..43538cb7c69 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -20,6 +20,15 @@ select * from t1 where a = 2; a b 2 NULL 2 2 +select * from t1 where a > 8; +a b +select * from t1 where a not between 8 and 8; +a b +2 NULL +2 2 +3 NULL +1 NULL +1 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index ff625acdb1d..4edb03405b5 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -14,6 +14,9 @@ partition by list column_list(a,b) column_list(NULL, NULL)), partition p1 values in (column_list(1,1), column_list(2,2)), partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +# +# BUG#47754 Crash when selecting using NOT BETWEEN for column list partitioning +# insert into t1 values (3, NULL); insert into t1 values (NULL, 1); insert into t1 values (NULL, NULL); @@ -23,6 +26,8 @@ insert into t1 values (1,1); insert into t1 values (2,2); select * from t1 where a = 1; select * from t1 where a = 2; +select * from t1 where a > 8; +select * from t1 where a not between 8 and 8; show create table t1; drop table t1; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 05b3822ce43..898cf8f07cd 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6962,7 +6962,15 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, nparts); } if (flags & NO_MAX_RANGE) - part_iter->part_nums.end= part_info->num_parts; + { + if (part_info->part_type == RANGE_PARTITION) + part_iter->part_nums.end= part_info->num_parts; + else /* LIST_PARTITION */ + { + DBUG_ASSERT(part_info->part_type == LIST_PARTITION); + part_iter->part_nums.end= part_info->num_list_values; + } + } else { // Copy from max_value to record From 328dabf473fad0e8bfe3bc0cc86b2c1df57c47a6 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Fri, 2 Oct 2009 19:16:06 +0800 Subject: [PATCH 070/274] Post fix SEMISYNC_PLUGIN_OPT when semi-sync plugins are not found mysql-test/mysql-test-run.pl: Set SEMISYNC_PLUGIN_OPT to '--plugin-dir=' when semi-sync plugins are not found --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index d50195c7d16..1c14104957d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1836,7 +1836,7 @@ sub environment_setup { { $ENV{'SEMISYNC_MASTER_PLUGIN'}= ""; $ENV{'SEMISYNC_SLAVE_PLUGIN'}= ""; - $ENV{'SEMISYNC_PLUGIN_OPT'}=""; + $ENV{'SEMISYNC_PLUGIN_OPT'}="--plugin-dir="; } # ---------------------------------------------------- From db72514486cefcbd21c80603df3b57ad1d8e696c Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Fri, 2 Oct 2009 16:15:54 +0300 Subject: [PATCH 071/274] fixing tests results: rpl_ndb_log, rpl_ndb_multi, sp_trans_log; adding replicate-ignore_server_ids specific tests --- mysql-test/r/sp_trans_log.result | 10 -- .../suite/rpl/r/rpl_server_id_ignore.result | 46 +++++++ .../rpl/t/rpl_server_id_ignore-slave.opt | 1 + .../suite/rpl/t/rpl_server_id_ignore.test | 114 ++++++++++++++++++ mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result | 2 + .../suite/rpl_ndb/r/rpl_ndb_multi.result | 4 +- 6 files changed, 165 insertions(+), 12 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_server_id_ignore.result create mode 100644 mysql-test/suite/rpl/t/rpl_server_id_ignore-slave.opt create mode 100644 mysql-test/suite/rpl/t/rpl_server_id_ignore.test diff --git a/mysql-test/r/sp_trans_log.result b/mysql-test/r/sp_trans_log.result index 3eec6f70063..117f6de754a 100644 --- a/mysql-test/r/sp_trans_log.result +++ b/mysql-test/r/sp_trans_log.result @@ -14,15 +14,5 @@ end| reset master| insert into t2 values (bug23333(),1)| ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -show binlog events from | -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `test`; BEGIN -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # use `test`; ROLLBACK -select count(*),@a from t1 /* must be 1,1 */| -count(*) @a -1 1 drop table t1,t2; drop function if exists bug23333; diff --git a/mysql-test/suite/rpl/r/rpl_server_id_ignore.result b/mysql-test/suite/rpl/r/rpl_server_id_ignore.result new file mode 100644 index 00000000000..cba6571eb1a --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_server_id_ignore.result @@ -0,0 +1,46 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +master_id: 1 +stop slave; +*** --replicate-same-server-id and change master option can clash *** +change master to IGNORE_SERVER_IDS= (2, 1); +ERROR HY000: The requested server id 2 clashes with the slave startup option --replicate-same-server-id +*** must be empty due to the error *** +ignore server id list: +change master to IGNORE_SERVER_IDS= (10, 100); +*** must be 10, 100 *** +ignore server id list: 10, 100 +reset slave; +*** must be empty due to reset slave *** +ignore server id list: 10, 100 +change master to IGNORE_SERVER_IDS= (10, 100); +*** CHANGE MASTER with IGNORE_SERVER_IDS option overrides (does not increment) the previous setup *** +change master to IGNORE_SERVER_IDS= (5, 1, 4, 3, 1); +*** must be 1, 3, 4, 5 due to overriding policy *** +ignore server id list: 1, 3, 4, 5 +*** ignore master (server 1) queries for a while *** +start slave; +create table t1 (n int); +*** must be empty as the event is to be filtered out *** +show tables; +Tables_in_test +*** allowing events from master *** +stop slave; +reset slave; +change master to IGNORE_SERVER_IDS= (10, 100); +*** the list must remain (10, 100) after reset slave *** +change master to IGNORE_SERVER_IDS= (); +*** must be empty due to IGNORE_SERVER_IDS empty list *** +ignore server id list: +change master to master_host='127.0.0.1', master_port=MASTER_PORT, master_user='root'; +start slave; +*** must have caught create table *** +show tables; +Tables_in_test +t1 +drop table t1; +end of the tests diff --git a/mysql-test/suite/rpl/t/rpl_server_id_ignore-slave.opt b/mysql-test/suite/rpl/t/rpl_server_id_ignore-slave.opt new file mode 100644 index 00000000000..302889525dd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_server_id_ignore-slave.opt @@ -0,0 +1 @@ +--disable-log-slave-updates --replicate-same-server-id diff --git a/mysql-test/suite/rpl/t/rpl_server_id_ignore.test b/mysql-test/suite/rpl/t/rpl_server_id_ignore.test new file mode 100644 index 00000000000..1b38bd34d3d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_server_id_ignore.test @@ -0,0 +1,114 @@ +# This test checks that the slave rejects events originating +# by a server from the list of ignored originators (bug#27808 etc) +# +# phases of tests: +# +# 0. master_id new line in show slave status +# 1. syntax related: +# a. error reporting if options clash; +# b. overriding the old IGNORE_SERVER_IDS setup by the following +# CHANGE MASTER ... IGNORE_SERVER_IDS= (list); +# c. the old setup preserving by CHANGE MASTER w/o IGNORE_SERVER_IDS +# d. resetting the ignored server ids with the empty list arg to +# IGNORE_SERVER_IDS=() +# e. RESET SLAVE preserves the list +# 2. run time related: +# a. observing no processing events from a master listed in IGNORE_SERVER_IDS +# b. nullifying the list and resuming of taking binlog from the very beginning with +# executing events this time + +source include/master-slave.inc; + +connection slave; + +# a new line for master_id +let $master_id= query_get_value(SHOW SLAVE STATUS, Master_Server_Id, 1); +echo master_id: $master_id; + +stop slave; +--echo *** --replicate-same-server-id and change master option can clash *** +--error ER_SLAVE_IGNORE_SERVER_IDS +change master to IGNORE_SERVER_IDS= (2, 1); +--echo *** must be empty due to the error *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; + +change master to IGNORE_SERVER_IDS= (10, 100); +--echo *** must be 10, 100 *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; +reset slave; +--echo *** must be empty due to reset slave *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; +change master to IGNORE_SERVER_IDS= (10, 100); +--echo *** CHANGE MASTER with IGNORE_SERVER_IDS option overrides (does not increment) the previous setup *** +change master to IGNORE_SERVER_IDS= (5, 1, 4, 3, 1); +--echo *** must be 1, 3, 4, 5 due to overriding policy *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; +--echo *** ignore master (server 1) queries for a while *** +start slave; + +connection master; + +#connection slave; +sync_slave_with_master; +let $slave_relay_pos0= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1); + +connection master; +create table t1 (n int); +let $master_binlog_end= query_get_value(SHOW MASTER STATUS, Position, 1); + +connection slave; +let $slave_param= Exec_Master_Log_Pos; +let $slave_param_value= $master_binlog_end; +source include/wait_for_slave_param.inc; +--echo *** must be empty as the event is to be filtered out *** +show tables; +--echo *** allowing events from master *** +let $slave_relay_pos1= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1); +# +# checking stability of relay log pos +# +if (`select $slave_relay_pos1 - $slave_relay_pos0`) +{ + --echo Error: relay log position changed: $slave_relay_pos0, $slave_relay_pos1 + query_vertical show slave status; +} + +stop slave; +source include/wait_for_slave_to_stop.inc; +reset slave; +change master to IGNORE_SERVER_IDS= (10, 100); +--echo *** the list must remain (10, 100) after reset slave *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); + +change master to IGNORE_SERVER_IDS= (); +--echo *** must be empty due to IGNORE_SERVER_IDS empty list *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1', master_port=$MASTER_MYPORT, master_user='root'; +start slave; + +connection master; + +#connection slave; +sync_slave_with_master; +--echo *** must have caught create table *** +show tables; + +# cleanup +connection master; +drop table t1; +#connection slave +sync_slave_with_master; + +--echo end of the tests + + + + + + diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result index 86752fbc4b8..301f4c2e45b 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result @@ -299,6 +299,8 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +Replicate_Ignore_Server_Ids +Master_Server_Id 1 show binlog events in 'slave-bin.000005' from 4; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log DROP TABLE t1; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_multi.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_multi.result index f8eb5ebdd89..66eeaa6357c 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_multi.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_multi.result @@ -26,11 +26,11 @@ stop slave; SELECT @the_pos:=Position,@the_file:=SUBSTRING_INDEX(FILE, '/', -1) FROM mysql.ndb_binlog_index WHERE epoch = ; @the_pos:=Position @the_file:=SUBSTRING_INDEX(FILE, '/', -1) -106 master-bin.000001 +107 master-bin.000001 CHANGE MASTER TO master_port=, master_log_file = 'master-bin.000001', -master_log_pos = 106 ; +master_log_pos = 107 ; start slave; INSERT INTO t1 VALUES ("row2","will go away",2),("row3","will change",3),("row4","D",4); DELETE FROM t1 WHERE c3 = 1; From 3aae87ad9260b91361cdafefd97ba3ebe3b00b0b Mon Sep 17 00:00:00 2001 From: Serge Kozlov Date: Fri, 2 Oct 2009 23:24:40 +0400 Subject: [PATCH 072/274] WL#4641 Heartbeat testing This is backport for next-mr. The patch adds new test cases that cover replication heartbeat testing. --- mysql-test/include/have_ssl_communication.inc | 4 + .../suite/rpl/r/rpl_heartbeat_2slaves.result | 55 ++ .../suite/rpl/r/rpl_heartbeat_basic.result | 304 ++++++++++ .../suite/rpl/r/rpl_heartbeat_ssl.result | 27 + .../suite/rpl/t/rpl_heartbeat_2slaves.cnf | 17 + .../suite/rpl/t/rpl_heartbeat_2slaves.test | 142 +++++ .../suite/rpl/t/rpl_heartbeat_basic.cnf | 7 + .../suite/rpl/t/rpl_heartbeat_basic.test | 536 ++++++++++++++++++ mysql-test/suite/rpl/t/rpl_heartbeat_ssl.test | 54 ++ 9 files changed, 1146 insertions(+) create mode 100644 mysql-test/include/have_ssl_communication.inc create mode 100644 mysql-test/suite/rpl/r/rpl_heartbeat_2slaves.result create mode 100644 mysql-test/suite/rpl/r/rpl_heartbeat_basic.result create mode 100644 mysql-test/suite/rpl/r/rpl_heartbeat_ssl.result create mode 100644 mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.cnf create mode 100644 mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test create mode 100644 mysql-test/suite/rpl/t/rpl_heartbeat_basic.cnf create mode 100644 mysql-test/suite/rpl/t/rpl_heartbeat_basic.test create mode 100644 mysql-test/suite/rpl/t/rpl_heartbeat_ssl.test diff --git a/mysql-test/include/have_ssl_communication.inc b/mysql-test/include/have_ssl_communication.inc new file mode 100644 index 00000000000..6f2d5587a75 --- /dev/null +++ b/mysql-test/include/have_ssl_communication.inc @@ -0,0 +1,4 @@ +-- require r/have_ssl.require +disable_query_log; +show variables like 'have_ssl'; +enable_query_log; diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat_2slaves.result b/mysql-test/suite/rpl/r/rpl_heartbeat_2slaves.result new file mode 100644 index 00000000000..ecb7c62c488 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_heartbeat_2slaves.result @@ -0,0 +1,55 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; + +*** Preparing *** +[on slave] +include/stop_slave.inc +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1, MASTER_LOG_FILE='MASTER_BINLOG'; +include/start_slave.inc +[on slave1] +STOP SLAVE; +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=1, MASTER_LOG_FILE='MASTER_BINLOG'; +include/start_slave.inc + +*** 2 slaves *** +Slave has received heartbeat event +Slave1 has received heartbeat event +Slave has received more heartbeats than Slave1 (1 means 'yes'): 1 + +*** Master->data->Slave1->heartbeat->Slave: *** +[on slave1] +RESET MASTER; +[on slave] +include/stop_slave.inc +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=SLAVE1_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.2, MASTER_LOG_FILE='SLAVE1_BINLOG'; +include/start_slave.inc +Slave has received heartbeat event +[on master] +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10), c LONGTEXT); +INSERT INTO t1 VALUES (1, 'on master', ''); +SHOW TABLES; +Tables_in_test +t1 +[on slave1] +SHOW TABLES; +Tables_in_test +t1 +[on slave] +SHOW TABLES; +Tables_in_test +[on master] +creating updates on master and send to slave1 during 5 second +[on slave] +Slave has received heartbeats (1 means 'yes'): 1 + +*** Clean up *** +DROP TABLE t1; + +End of 6.0 test diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result b/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result new file mode 100644 index 00000000000..ddb2122c631 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result @@ -0,0 +1,304 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; + +*** Preparing *** +include/stop_slave.inc +RESET SLAVE; +SET @restore_slave_net_timeout=@@global.slave_net_timeout; +RESET MASTER; +SET @restore_slave_net_timeout=@@global.slave_net_timeout; +SET @restore_event_scheduler=@@global.event_scheduler; + +*** Default value *** +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root'; +slave_net_timeout/slave_heartbeat_timeout=2.0000 +RESET SLAVE; + +*** Reset slave affect *** +SET @@global.slave_net_timeout=30; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +RESET SLAVE; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 15.000 + +*** Default value if slave_net_timeout changed *** +SET @@global.slave_net_timeout=50; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root'; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 25.000 +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +RESET SLAVE; + +*** Warning if updated slave_net_timeout < slave_heartbeat_timeout *** +SET @@global.slave_net_timeout=FLOOR(SLAVE_HEARTBEAT_TIMEOUT)-1; +Warnings: +Warning 1624 The currect value for master_heartbeat_period exceeds the new value of `slave_net_timeout' sec. A sensible value for the period should be less than the timeout. +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +RESET SLAVE; + +*** Warning if updated slave_heartbeat_timeout > slave_net_timeout *** +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=SLAVE_NET_TIMEOUT; +Warnings: +Warning 1624 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' sec. A sensible value for the period should be less than the timeout. +RESET SLAVE; + +*** CHANGE MASTER statement only updates slave_heartbeat_period *** +SET @@global.slave_net_timeout=20; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +SHOW VARIABLES LIKE 'slave_net_timeout'; +Variable_name Value +slave_net_timeout 20 +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 5.000 +SET @@global.slave_net_timeout=2*@@global.slave_net_timeout; +SHOW VARIABLES LIKE 'slave_net_timeout'; +Variable_name Value +slave_net_timeout 40 +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 5.000 +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +RESET SLAVE; + +*** Update slave_net_timeout on master *** +SET @@global.slave_net_timeout=500; +SET @@global.slave_net_timeout=200; +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root'; +include/start_slave.inc +SHOW VARIABLES LIKE 'slave_net_timeout'; +Variable_name Value +slave_net_timeout 200 +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 100.000 +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +include/stop_slave.inc +RESET SLAVE; +SET @@global.slave_net_timeout=@restore_slave_net_timeout; + +*** Start/stop slave *** +SET @@global.slave_net_timeout=100; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=20; +include/start_slave.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 20.000 +include/stop_slave.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 20.000 + +*** Reload slave *** +SET @@global.slave_net_timeout=50; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=30; +Reload slave +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 30.000 +SET @restore_slave_net_timeout=@@global.slave_net_timeout; + +*** Disable heartbeat *** +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 0.000 +SHOW STATUS LIKE 'slave_received_heartbeats'; +Variable_name Value +Slave_received_heartbeats 0 +include/start_slave.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 0.000 +SHOW STATUS LIKE 'slave_received_heartbeats'; +Variable_name Value +Slave_received_heartbeats 0 +include/stop_slave.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 0.000 +SHOW STATUS LIKE 'slave_received_heartbeats'; +Variable_name Value +Slave_received_heartbeats 0 +RESET SLAVE; +SELECT SLAVE_HEARTBEAT_TIMEOUT = 0 AS Result; +Result +0 + +*** Min slave_heartbeat_timeout *** +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.001; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 0.001 +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.0009; +Warnings: +Warning 1624 The requested value for the heartbeat period is less than 1 msec. The period is reset to zero which means no heartbeats will be sending +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 0.000 +RESET SLAVE; + +*** Max slave_heartbeat_timeout *** +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294967; +Warnings: +Warning 1624 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' sec. A sensible value for the period should be less than the timeout. +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 4294967.000 +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294968; +ERROR HY000: The requested value for the heartbeat period is negative or exceeds the maximum 4294967 seconds +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=8589935; +ERROR HY000: The requested value for the heartbeat period is negative or exceeds the maximum 4294967 seconds +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294967296; +ERROR HY000: The requested value for the heartbeat period is negative or exceeds the maximum 4294967 seconds +RESET SLAVE; + +*** Misc incorrect values *** +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD='-1'; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''-1'' at line 1 +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD='123abc'; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''123abc'' at line 1 +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=''; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '''' at line 1 +RESET SLAVE; + +*** Running slave *** +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +include/start_slave.inc +Heartbeat event received + +*** Stopped slave *** +include/stop_slave.inc +Number of received heartbeat events while slave stopped: 0 + +*** Started slave *** +include/start_slave.inc +Heartbeat event received + +*** Stopped IO thread *** +STOP SLAVE IO_THREAD; +Number of received heartbeat events while io thread stopped: 0 + +*** Started IO thread *** +START SLAVE IO_THREAD; +Heartbeat event received + +*** Stopped SQL thread *** +STOP SLAVE SQL_THREAD; +Heartbeat events are received while sql thread stopped (1 means 'yes'): 1 + +*** Started SQL thread *** +START SLAVE SQL_THREAD; +Heartbeat event received + +*** Stopped SQL thread by error *** +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10), c LONGTEXT); +INSERT INTO t1 VALUES (1, 'on slave', NULL); +INSERT INTO t1 VALUES (1, 'on master', NULL); +Heartbeat events are received while sql thread stopped (1 means 'yes'): 1 +include/stop_slave.inc +DROP TABLE t1; + +*** Master send to slave *** +CREATE EVENT e1 +ON SCHEDULE EVERY 1 SECOND +DO +BEGIN +UPDATE test.t1 SET a = a + 1 WHERE a < 10; +END| +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=1.5; +include/start_slave.inc +SET @@global.event_scheduler=1; +SHOW STATUS LIKE 'slave_received_heartbeats'; +Variable_name Value +Slave_received_heartbeats 0 +SHOW STATUS LIKE 'slave_received_heartbeats'; +Variable_name Value +Slave_received_heartbeats 0 +DELETE FROM t1; +DROP EVENT e1; + +*** Flush logs on slave *** +STOP SLAVE; +RESET SLAVE; +DROP TABLE t1; +DROP TABLE t1; +RESET MASTER; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.5; +include/start_slave.inc +Heartbeat events are received while rotation of relay logs (1 means 'yes'): 1 + +*** Compressed protocol *** +SET @@global.slave_compressed_protocol=1; +include/stop_slave.inc +RESET SLAVE; +SET @@global.slave_compressed_protocol=1; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +include/start_slave.inc +Heartbeat event received +SET @@global.slave_compressed_protocol=0; +SET @@global.slave_compressed_protocol=0; + +*** Reset master *** +STOP SLAVE; +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +include/start_slave.inc +RESET MASTER; +Heartbeat events are received after reset of master (1 means 'yes'): 1 + +*** Reload master *** +STOP SLAVE; +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +include/start_slave.inc +Heartbeat event received +Reload master +Heartbeat event received + +*** Circular replication *** +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10)); +include/stop_slave.inc +RESET MASTER; +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1, MASTER_LOG_FILE='MASTER_BINLOG'; +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=SLAVE_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=1, MASTER_LOG_FILE='SLAVE_BINLOG'; +include/start_slave.inc +INSERT INTO t1 VALUES(1, 'on master'); +include/start_slave.inc +INSERT INTO t1 VALUES(2, 'on slave'); +SELECT * FROM t1 ORDER BY a; +a b +1 on master +2 on slave +SELECT * FROM t1 ORDER BY a; +a b +1 on master +2 on slave +Heartbeat event received on master +Heartbeat event received on slave +Slave has received more events than master (1 means 'yes'): 1 + +*** Clean up *** +include/stop_slave.inc +DROP TABLE t1; +include/stop_slave.inc +SET @@global.slave_net_timeout=@restore_slave_net_timeout; + +End of 6.0 test diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat_ssl.result b/mysql-test/suite/rpl/r/rpl_heartbeat_ssl.result new file mode 100644 index 00000000000..42de3c459cb --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_heartbeat_ssl.result @@ -0,0 +1,27 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; + +*** Heartbeat over SSL *** +include/stop_slave.inc +RESET SLAVE; +CHANGE MASTER TO +MASTER_HOST='127.0.0.1', +MASTER_PORT=MASTER_PORT, +MASTER_USER='root', +MASTER_HEARTBEAT_PERIOD=0.1, +MASTER_LOG_FILE='MASTER_BINLOG', +MASTER_SSL=1, +MASTER_SSL_CA='MYSQL_TEST_DIR/std_data/cacert.pem', +MASTER_SSL_CERT='MYSQL_TEST_DIR/std_data/client-cert.pem', +MASTER_SSL_KEY='MYSQL_TEST_DIR/std_data/client-key.pem'; +include/start_slave.inc +Master_SSL_Allowed: Yes +Heartbeat event has received + +*** Clean up *** + +End of 6.0 test diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.cnf b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.cnf new file mode 100644 index 00000000000..a3ed77c8bd2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.cnf @@ -0,0 +1,17 @@ +!include ../my.cnf + +[mysqld.1] +server_id=1 + +[mysqld.2] +server_id=2 + +[mysqld.3] +server_id=3 + +[ENV] +SLAVE_MYPORT1= @mysqld.3.port +SLAVE_MYSOCK1= @mysqld.3.socket + + + diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test new file mode 100644 index 00000000000..81737feea9e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test @@ -0,0 +1,142 @@ +############################################################# +# Author: Serge Kozlov +# Date: 02/19/2009 +# Purpose: Testing heartbeat for schema +# 1 master and 2 slaves +############################################################# +--source include/master-slave.inc +--echo + +--echo *** Preparing *** +--connection master +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +--connection slave +--echo [on slave] +--source include/stop_slave.inc +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT $binlog_file MASTER_BINLOG +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1, MASTER_LOG_FILE='$binlog_file'; +--source include/start_slave.inc +--disconnect slave1 +--connect(slave1,127.0.0.1,root,,test,$SLAVE_MYPORT1,) +--connection slave1 +--echo [on slave1] +--disable_warnings +STOP SLAVE; +--enable_warnings +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT $binlog_file MASTER_BINLOG +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=1, MASTER_LOG_FILE='$binlog_file'; +--source include/start_slave.inc +--echo + +# +# Testing heartbeat +# + +# Check that heartbeat events sent to both slaves with correct periods +--echo *** 2 slaves *** +--connection slave +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Slave has received heartbeat event +--connection slave1 +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +let $slave1_rcvd_heartbeats= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--echo Slave1 has received heartbeat event +--connection slave +let $slave_rcvd_heartbeats= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($slave_rcvd_heartbeats DIV $slave1_rcvd_heartbeats) > 1 AS Result, Result, 1); +--echo Slave has received more heartbeats than Slave1 (1 means 'yes'): $result +--echo + + +# Create topology A->B->C and check that C receives heartbeat while B gets data +# Slave1 (B) started w/o --log-slave-updates because B should not send data from A to C +--echo *** Master->data->Slave1->heartbeat->Slave: *** +--connection slave1 +--echo [on slave1] +RESET MASTER; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +--connection slave +--echo [on slave] +--source include/stop_slave.inc +RESET SLAVE; +--replace_result $SLAVE_MYPORT1 SLAVE1_PORT $binlog_file SLAVE1_BINLOG +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$SLAVE_MYPORT1, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.2, MASTER_LOG_FILE='$binlog_file'; +--source include/start_slave.inc +# Check heartbeat for new replication channel slave1->slave +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Slave has received heartbeat event +--connection master +--echo [on master] +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10), c LONGTEXT); +INSERT INTO t1 VALUES (1, 'on master', ''); +--save_master_pos +SHOW TABLES; +--connection slave1 +--sync_with_master 0 +--echo [on slave1] +SHOW TABLES; +let $slave_pos_before= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1); +--save_master_pos +--connection slave +--sync_with_master 0 +--echo [on slave] +SHOW TABLES; +--connection master +--echo [on master] +--echo creating updates on master and send to slave1 during 5 second +# Generate events on master and send to slave1 during 5 second +let $i= 1; +let $j= 1; +let $k= 1; +--disable_query_log +while ($i) { + eval SET @c_text=REPEAT('1234567890', $j); + eval UPDATE t1 SET a=$j, c=@c_text; + --connection slave1 + let $slave_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1); + if (`SELECT ($k*($slave_pos - $slave_pos_before)) > 0`) { + --connection slave + let $slave_rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); + let $k= 0; + let $time_before = `SELECT NOW()`; + } + if (`SELECT ((1-$k)*TIMESTAMPDIFF(SECOND,'$time_before',NOW())) > 5`) { + --connection slave + let $slave_rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); + let $i= 0; + } + --connection master + inc $j; + sleep 0.1; +} +--enable_query_log +--connection slave +--echo [on slave] +let $result= query_get_value(SELECT ($slave_rcvd_heartbeats_after - $slave_rcvd_heartbeats_before) > 0 AS Result, Result, 1); +--echo Slave has received heartbeats (1 means 'yes'): $result +--echo + +# +# Clean up +# +--echo *** Clean up *** +--connection master +DROP TABLE t1; +--save_master_pos +--connection slave1 +--sync_with_master 0 +--echo + +# End of 6.0 test +--echo End of 6.0 test diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.cnf b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.cnf new file mode 100644 index 00000000000..a4a291bca79 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.cnf @@ -0,0 +1,7 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates + +[mysqld.2] +log-slave-updates diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test new file mode 100644 index 00000000000..198f1208344 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test @@ -0,0 +1,536 @@ +############################################################# +# Author: Serge Kozlov +# Date: 02/19/2009 +# Purpose: Testing basic functionality of heartbeat. +# Description: +# * Testing different values for slave_heartbeat_period. +# * How to affect various statements to slave_heartbeat_period +# * Various states of slave and heartbeat +# * Various states of master and heartbeat +# * Circular replication +############################################################# +--source include/master-slave.inc +--echo + +--echo *** Preparing *** +--connection slave +--source include/stop_slave.inc +RESET SLAVE; +SET @restore_slave_net_timeout=@@global.slave_net_timeout; +let $slave_heartbeat_timeout= query_get_value(SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period', Value, 1); +--disable_query_log +eval SET @restore_slave_heartbeat_timeout=$slave_heartbeat_timeout; +--enable_query_log + +--connection master +RESET MASTER; +SET @restore_slave_net_timeout=@@global.slave_net_timeout; +SET @restore_event_scheduler=@@global.event_scheduler; +--echo + +# +# Test slave_heartbeat_period +# + +--connection slave + +# Default value of slave_heartbeat_timeout = slave_net_timeout/2 +--echo *** Default value *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root'; +let $slave_net_timeout= query_get_value(SHOW VARIABLES LIKE 'slave_net_timeout', Value, 1); +let $slave_heartbeat_timeout= query_get_value(SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period', Value, 1); +let $result= query_get_value(SELECT $slave_net_timeout/$slave_heartbeat_timeout AS Result, Result, 1); +--echo slave_net_timeout/slave_heartbeat_timeout=$result +RESET SLAVE; +--echo + +# Reset slave set slave_heartbeat_timeout = slave_net_timeout/2 +--echo *** Reset slave affect *** +--disable_warnings +SET @@global.slave_net_timeout=30; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +RESET SLAVE; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +--echo + +# Check default value of slave_heartbeat_timeout if slave_net_timeout is changed +--echo *** Default value if slave_net_timeout changed *** +--disable_warnings +SET @@global.slave_net_timeout=50; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root'; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +RESET SLAVE; +--echo + +# Set slave_net_timeout less than current value of slave_heartbeat_period +--echo *** Warning if updated slave_net_timeout < slave_heartbeat_timeout *** +let $slave_heartbeat_timeout= query_get_value(SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period', Value, 1); +--replace_result $slave_heartbeat_timeout SLAVE_HEARTBEAT_TIMEOUT +eval SET @@global.slave_net_timeout=FLOOR($slave_heartbeat_timeout)-1; +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +RESET SLAVE; +--echo + +# Set value of slave_heartbeat_period greater than slave_net_timeout +--echo *** Warning if updated slave_heartbeat_timeout > slave_net_timeout *** +let $slave_net_timeout= query_get_value(SHOW VARIABLES LIKE 'slave_net_timeout', Value, 1); +inc $slave_net_timeout; +--replace_result $MASTER_MYPORT MASTER_PORT $slave_net_timeout SLAVE_NET_TIMEOUT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=$slave_net_timeout; +RESET SLAVE; +--echo + +# Changing of slave_net_timeout shouldn't affect to current value of slave_heartbeat_period +--echo *** CHANGE MASTER statement only updates slave_heartbeat_period *** +--disable_warnings +SET @@global.slave_net_timeout=20; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +SHOW VARIABLES LIKE 'slave_net_timeout'; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @@global.slave_net_timeout=2*@@global.slave_net_timeout; +SHOW VARIABLES LIKE 'slave_net_timeout'; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +RESET SLAVE; +--echo + +# Master value of slave_net_timeout shouldn't affect to slave's slave_heartbeat_period +--echo *** Update slave_net_timeout on master *** +--connection master +--disable_warnings +SET @@global.slave_net_timeout=500; +--enable_warnings +--connection slave +SET @@global.slave_net_timeout=200; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root'; +--source include/start_slave.inc +--sync_with_master +SHOW VARIABLES LIKE 'slave_net_timeout'; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +--source include/stop_slave.inc +RESET SLAVE; +--connection master +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +--echo + +# Start/stop slave shouldn't change slave_heartbeat_period +--echo *** Start/stop slave *** +--connection slave +--disable_warnings +SET @@global.slave_net_timeout=100; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=20; +--source include/start_slave.inc +--sync_with_master +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +--source include/stop_slave.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +--echo + +# Reload slave shouldn't change slave_heartbeat_period +--echo *** Reload slave *** +--connection slave +--disable_warnings +SET @@global.slave_net_timeout=50; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=30; +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--echo Reload slave +--shutdown_server 10 +--source include/wait_until_disconnected.inc +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @restore_slave_net_timeout=@@global.slave_net_timeout; +--echo + +# Disable heartbeat +--echo *** Disable heartbeat *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SHOW STATUS LIKE 'slave_received_heartbeats'; +--source include/start_slave.inc +--sync_with_master +--sleep 2 +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SHOW STATUS LIKE 'slave_received_heartbeats'; +--source include/stop_slave.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SHOW STATUS LIKE 'slave_received_heartbeats'; +RESET SLAVE; +let $slave_heartbeat_timeout= query_get_value(SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period', Value, 1); +--replace_result $slave_heartbeat_timeout SLAVE_HEARTBEAT_TIMEOUT +--eval SELECT $slave_heartbeat_timeout = 0 AS Result +--echo + +# +# Check limits for slave_heartbeat_timeout +# + +--echo *** Min slave_heartbeat_timeout *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.001; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.0009; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +RESET SLAVE; +--echo + +--echo *** Max slave_heartbeat_timeout *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294967; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294968; +RESET SLAVE; +# Check double size of max allowed value for master_heartbeat_period +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=8589935; +RESET SLAVE; +# Check 2^32 +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294967296; +RESET SLAVE; +--echo + +--echo *** Misc incorrect values *** +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_PARSE_ERROR +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD='-1'; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_PARSE_ERROR +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD='123abc'; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_PARSE_ERROR +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=''; +RESET SLAVE; +--echo + +# +# Testing heartbeat +# + +# Check received heartbeat events for running slave +--echo *** Running slave *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc +--sync_with_master +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Check received heartbeat events for stopped slave +--echo *** Stopped slave *** +--source include/stop_slave.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +sleep 2; +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) AS Result, Result, 1); +--echo Number of received heartbeat events while slave stopped: $result +--echo + +# Check received heartbeat events for started slave +--echo *** Started slave *** +--source include/start_slave.inc +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Check received heartbeat events for stopped IO thread +--echo *** Stopped IO thread *** +STOP SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_stop.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +sleep 2; +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) AS Result, Result, 1); +--echo Number of received heartbeat events while io thread stopped: $result +--echo + +# Check received heartbeat events for started IO thread +--echo *** Started IO thread *** +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Check received heartbeat events for stopped SQL thread +--echo *** Stopped SQL thread *** +STOP SLAVE SQL_THREAD; +--source include/wait_for_slave_sql_to_stop.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +sleep 2; +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) > 0 AS Result, Result, 1); +--echo Heartbeat events are received while sql thread stopped (1 means 'yes'): $result +--echo + +# Check received heartbeat events for started SQL thread +--echo *** Started SQL thread *** +START SLAVE SQL_THREAD; +--source include/wait_for_slave_sql_to_start.inc +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Check received heartbeat event for stopped SQL thread by error +--echo *** Stopped SQL thread by error *** +--connection master +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10), c LONGTEXT); +--sync_slave_with_master +INSERT INTO t1 VALUES (1, 'on slave', NULL); +--connection master +INSERT INTO t1 VALUES (1, 'on master', NULL); +--connection slave +let $slave_errno= ER_DUP_ENTRY +--source include/wait_for_slave_sql_error.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +sleep 2; +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) > 0 AS Result, Result, 1); +--echo Heartbeat events are received while sql thread stopped (1 means 'yes'): $result +--source include/stop_slave.inc +DROP TABLE t1; +--echo + +# Check received heartbeat events while master send events to slave +--echo *** Master send to slave *** +--connection master +# Create the event that will update table t1 every second +DELIMITER |; +CREATE EVENT e1 + ON SCHEDULE EVERY 1 SECOND + DO + BEGIN + UPDATE test.t1 SET a = a + 1 WHERE a < 10; + END| +DELIMITER ;| +--connection slave +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=1.5; +--source include/start_slave.inc +--connection master +# Enable scheduler +SET @@global.event_scheduler=1; +--connection slave +SHOW STATUS LIKE 'slave_received_heartbeats'; +--sync_with_master +# Wait some updates for table t1 from master +let $wait_condition= SELECT COUNT(*)=1 FROM t1 WHERE a > 5; +--source include/wait_condition.inc +SHOW STATUS LIKE 'slave_received_heartbeats'; +--connection master +DELETE FROM t1; +DROP EVENT e1; +--echo + +# Check received heartbeat events while logs flushed on slave +--connection slave +--echo *** Flush logs on slave *** +STOP SLAVE; +RESET SLAVE; +DROP TABLE t1; +--connection master +DROP TABLE t1; +RESET MASTER; +--connection slave +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.5; +let $slave_param_comparison= =; +--source include/start_slave.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +# Flush logs every 0.1 second during 5 sec +--disable_query_log +let $i=50; +while ($i) { + FLUSH LOGS; + dec $i; + sleep 0.1; +} +--enable_query_log +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) > 0 AS Result, Result, 1); +--echo Heartbeat events are received while rotation of relay logs (1 means 'yes'): $result +--echo + +# Use compressed protocol between master and slave +--echo *** Compressed protocol *** +--connection master +SET @@global.slave_compressed_protocol=1; +--connection slave +--source include/stop_slave.inc +RESET SLAVE; +SET @@global.slave_compressed_protocol=1; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received +SET @@global.slave_compressed_protocol=0; +--connection master +SET @@global.slave_compressed_protocol=0; +--echo + + +# Check received heartbeat events after reset of master +--echo *** Reset master *** +--connection slave +STOP SLAVE; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--connection master +RESET MASTER; +--enable_query_log +--sync_slave_with_master +--sleep 2 +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) > 0 AS Result, Result, 1); +--echo Heartbeat events are received after reset of master (1 means 'yes'): $result +--echo + +# Reloaded master should restore heartbeat +--echo *** Reload master *** +--connection slave +STOP SLAVE; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc +# Wait until slave_received_heartbeats will be incremented +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--connection master +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF +--echo Reload master +--shutdown_server 10 +--source include/wait_until_disconnected.inc +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc +--connection slave +# Wait until slave_received_heartbeats will be incremented +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Circular replication +--echo *** Circular replication *** +# Configure circular replication +--connection master +RESET MASTER; +let $master_binlog= query_get_value(SHOW MASTER STATUS, File, 1); +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10)); +--sync_slave_with_master +--source include/stop_slave.inc +RESET MASTER; +let $slave_binlog= query_get_value(SHOW MASTER STATUS, File, 1); +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT $master_binlog MASTER_BINLOG +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1, MASTER_LOG_FILE='$master_binlog'; +--connection master +RESET SLAVE; +--replace_result $SLAVE_MYPORT SLAVE_PORT $slave_binlog SLAVE_BINLOG +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$SLAVE_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=1, MASTER_LOG_FILE='$slave_binlog'; +--source include/start_slave.inc +# Insert data on master and on slave and make sure that it replicated for both directions +INSERT INTO t1 VALUES(1, 'on master'); +--save_master_pos +--connection slave +--source include/start_slave.inc +--sync_with_master +INSERT INTO t1 VALUES(2, 'on slave'); +--save_master_pos +--connection master +--sync_with_master +SELECT * FROM t1 ORDER BY a; +let $master_rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--connection slave +SELECT * FROM t1 ORDER BY a; +# Wait heartbeat event on master +--connection master +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received on master +let $master_rcvd_heartbeats= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +# Wait heartbeat event on slave +--connection slave +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received on slave +let $slave_rcvd_heartbeats= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +# Heartbeat period on slave less than on master therefore number of received events on slave +# should be greater than on master +let $result= query_get_value(SELECT ($slave_rcvd_heartbeats DIV $master_rcvd_heartbeats) > 1 AS Result, Result, 1); +--echo Slave has received more events than master (1 means 'yes'): $result +--echo + +# +# Clean up and restore system variables +# +--echo *** Clean up *** +--connection master +--source include/stop_slave.inc +DROP TABLE t1; +--sync_slave_with_master +--source include/stop_slave.inc +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +--echo + +# End of 6.0 test +--echo End of 6.0 test diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_ssl.test b/mysql-test/suite/rpl/t/rpl_heartbeat_ssl.test new file mode 100644 index 00000000000..6460b157b52 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_ssl.test @@ -0,0 +1,54 @@ +############################################################# +# Author: Serge Kozlov +# Date: 02/19/2009 +# Purpose: Testing basic functionality of heartbeat over SSL +############################################################# +--source include/have_ssl_communication.inc +--source include/master-slave.inc +--echo + +# +# Testing heartbeat over SSL +# + +# Heartbeat over SSL +--echo *** Heartbeat over SSL *** +--connection master +let $master_binlog= query_get_value(SHOW MASTER STATUS, File, 1); +--connection slave +--source include/stop_slave.inc +RESET SLAVE; +# Connect to master with SSL +--replace_result $MASTER_MYPORT MASTER_PORT $MYSQL_TEST_DIR MYSQL_TEST_DIR $master_binlog MASTER_BINLOG +eval CHANGE MASTER TO + MASTER_HOST='127.0.0.1', + MASTER_PORT=$MASTER_MYPORT, + MASTER_USER='root', + MASTER_HEARTBEAT_PERIOD=0.1, + MASTER_LOG_FILE='$master_binlog', + MASTER_SSL=1, + MASTER_SSL_CA='$MYSQL_TEST_DIR/std_data/cacert.pem', + MASTER_SSL_CERT='$MYSQL_TEST_DIR/std_data/client-cert.pem', + MASTER_SSL_KEY='$MYSQL_TEST_DIR/std_data/client-key.pem'; +--source include/start_slave.inc +# Check SSL state of slave +let $slave_ssl_status= query_get_value(SHOW SLAVE STATUS, Master_SSL_Allowed, 1); +--echo Master_SSL_Allowed: $slave_ssl_status +# Wait until hearbeat event will received +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event has received +--echo + +# +# Clean up +# +--echo *** Clean up *** +--connection master +--sync_slave_with_master +--echo + +# End of 6.0 test +--echo End of 6.0 test From d51bd44479d1192511f49daf112fa0e9280db526 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Sat, 3 Oct 2009 09:40:32 +0800 Subject: [PATCH 073/274] Post fix result file --- mysql-test/suite/rpl_ndb/r/rpl_ndb_sp006.result | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_sp006.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_sp006.result index 482d43c8f10..4675216f9a2 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_sp006.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_sp006.result @@ -4,7 +4,8 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -create database if not exists mysqltest1; +drop database if exists mysqltest1; +create database mysqltest1; DROP PROCEDURE IF EXISTS mysqltest1.p1; DROP PROCEDURE IF EXISTS mysqltest1.p2; DROP TABLE IF EXISTS mysqltest1.t2; From d8724a4538a61ea6f98fb770c951b89bde734f77 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Sat, 3 Oct 2009 13:00:05 +0800 Subject: [PATCH 074/274] Fix semisync master/slave status always showed as OFF on sparc On sparc, semisync master/slave status is always showed as OFF, this is fixed by change rpl_semisync_master/slave_status variables from long to char. plugin/semisync/semisync_master.cc: Change rpl_semisync_master_status variables from long to char plugin/semisync/semisync_master.h: Change rpl_semisync_master_status variables from long to char plugin/semisync/semisync_slave.cc: Change rpl_semisync_slave_status variables from long to char plugin/semisync/semisync_slave.h: Change rpl_semisync_slave_status variables from long to char --- plugin/semisync/semisync_master.cc | 2 +- plugin/semisync/semisync_master.h | 2 +- plugin/semisync/semisync_slave.cc | 2 +- plugin/semisync/semisync_slave.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/semisync/semisync_master.cc b/plugin/semisync/semisync_master.cc index b3454c49829..3641b658268 100644 --- a/plugin/semisync/semisync_master.cc +++ b/plugin/semisync/semisync_master.cc @@ -25,7 +25,7 @@ char rpl_semi_sync_master_enabled; unsigned long rpl_semi_sync_master_timeout; unsigned long rpl_semi_sync_master_trace_level; -unsigned long rpl_semi_sync_master_status = 0; +char rpl_semi_sync_master_status = 0; unsigned long rpl_semi_sync_master_yes_transactions = 0; unsigned long rpl_semi_sync_master_no_transactions = 0; unsigned long rpl_semi_sync_master_off_times = 0; diff --git a/plugin/semisync/semisync_master.h b/plugin/semisync/semisync_master.h index a1697b2ae67..bb63cece18a 100644 --- a/plugin/semisync/semisync_master.h +++ b/plugin/semisync/semisync_master.h @@ -347,7 +347,7 @@ class ReplSemiSyncMaster extern char rpl_semi_sync_master_enabled; extern unsigned long rpl_semi_sync_master_timeout; extern unsigned long rpl_semi_sync_master_trace_level; -extern unsigned long rpl_semi_sync_master_status; +extern char rpl_semi_sync_master_status; extern unsigned long rpl_semi_sync_master_yes_transactions; extern unsigned long rpl_semi_sync_master_no_transactions; extern unsigned long rpl_semi_sync_master_off_times; diff --git a/plugin/semisync/semisync_slave.cc b/plugin/semisync/semisync_slave.cc index f6bbb17ce9d..3298ce316a8 100644 --- a/plugin/semisync/semisync_slave.cc +++ b/plugin/semisync/semisync_slave.cc @@ -17,7 +17,7 @@ #include "semisync_slave.h" char rpl_semi_sync_slave_enabled; -unsigned long rpl_semi_sync_slave_status= 0; +char rpl_semi_sync_slave_status= 0; unsigned long rpl_semi_sync_slave_trace_level; int ReplSemiSyncSlave::initObject() diff --git a/plugin/semisync/semisync_slave.h b/plugin/semisync/semisync_slave.h index 73bc8aeeade..16fa31c69eb 100644 --- a/plugin/semisync/semisync_slave.h +++ b/plugin/semisync/semisync_slave.h @@ -94,6 +94,6 @@ private: /* System and status variables for the slave component */ extern char rpl_semi_sync_slave_enabled; extern unsigned long rpl_semi_sync_slave_trace_level; -extern unsigned long rpl_semi_sync_slave_status; +extern char rpl_semi_sync_slave_status; #endif /* SEMISYNC_SLAVE_H */ From 494cb46d838768194ba89eb6145f2d8a461bda48 Mon Sep 17 00:00:00 2001 From: Serge Kozlov Date: Sat, 3 Oct 2009 22:21:44 +0400 Subject: [PATCH 075/274] WL#3788 It is backport patch. This adds new test case for testing affects of some variables to replication. --- .../suite/rpl/r/rpl_spec_variables.result | 225 +++++++++++++ .../suite/rpl/t/rpl_spec_variables-slave.opt | 1 + .../suite/rpl/t/rpl_spec_variables.test | 306 ++++++++++++++++++ 3 files changed, 532 insertions(+) create mode 100644 mysql-test/suite/rpl/r/rpl_spec_variables.result create mode 100644 mysql-test/suite/rpl/t/rpl_spec_variables-slave.opt create mode 100644 mysql-test/suite/rpl/t/rpl_spec_variables.test diff --git a/mysql-test/suite/rpl/r/rpl_spec_variables.result b/mysql-test/suite/rpl/r/rpl_spec_variables.result new file mode 100644 index 00000000000..ea2778bf71c --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_spec_variables.result @@ -0,0 +1,225 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; + +* auto_increment_increment, auto_increment_offset * +SET @@global.auto_increment_increment=2; +SET @@session.auto_increment_increment=2; +SET @@global.auto_increment_offset=10; +SET @@session.auto_increment_offset=10; +SET @@global.auto_increment_increment=3; +SET @@session.auto_increment_increment=3; +SET @@global.auto_increment_offset=20; +SET @@session.auto_increment_offset=20; +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +INSERT INTO t1 (b) VALUES ('master'); +INSERT INTO t1 (b) VALUES ('master'); +SELECT * FROM t1 ORDER BY a; +a b +2 master +4 master +CREATE TABLE t2 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +INSERT INTO t1 (b) VALUES ('slave'); +INSERT INTO t1 (b) VALUES ('slave'); +INSERT INTO t2 (b) VALUES ('slave'); +INSERT INTO t2 (b) VALUES ('slave'); +SELECT * FROM t1 ORDER BY a; +a b +2 master +4 master +7 slave +10 slave +SELECT * FROM t2 ORDER BY a; +a b +1 slave +4 slave +DROP TABLE IF EXISTS t1,t2; +SET @@global.auto_increment_increment=1; +SET @@session.auto_increment_increment=1; +SET @@global.auto_increment_offset=1; +SET @@session.auto_increment_offset=1; +SET @@global.auto_increment_increment=1; +SET @@session.auto_increment_increment=1; +SET @@global.auto_increment_offset=1; +SET @@session.auto_increment_offset=1; +SET auto_increment_increment=1; +SET auto_increment_offset=1; + +* character_set_database, collation_server * +SET @restore_master_character_set_database=@@global.character_set_database; +SET @restore_master_collation_server=@@global.collation_server; +SET @@global.character_set_database=latin1; +SET @@session.character_set_database=latin1; +SET @@global.collation_server=latin1_german1_ci; +SET @@session.collation_server=latin1_german1_ci; +SET @restore_slave_character_set_database=@@global.character_set_database; +SET @restore_slave_collation_server=@@global.collation_server; +SET @@global.character_set_database=utf8; +SET @@session.character_set_database=utf8; +SET @@global.collation_server=utf8_bin; +SET @@session.collation_server=utf8_bin; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(10) COLLATE latin1_german1_ci DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german1_ci +CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(10) COLLATE latin1_german1_ci DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german1_ci +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) NOT NULL, + `b` varchar(10) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin +SET @@global.collation_server=latin1_swedish_ci; +SET @@session.collation_server=latin1_swedish_ci; +SET @@global.collation_server=latin1_swedish_ci; +SET @@session.collation_server=latin1_swedish_ci; +DROP TABLE IF EXISTS t1,t2; + +* default_week_format * +SET @@global.default_week_format=0; +SET @@session.default_week_format=0; +SET @@global.default_week_format=1; +SET @@session.default_week_format=1; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10), c INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 'master ', WEEK('2008-01-07')); +SELECT * FROM t1 ORDER BY a; +a b c +1 master 1 +INSERT INTO t1 VALUES (2, 'slave ', WEEK('2008-01-07')); +SELECT * FROM t1 ORDER BY a; +a b c +1 master 1 +2 slave 2 +DROP TABLE t1; +SET @@global.default_week_format=0; +SET @@session.default_week_format=0; + +* local_infile * +SET @@global.local_infile=0; +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(20), c CHAR(254)) ENGINE=MyISAM; +LOAD DATA LOCAL INFILE 'FILE' INTO TABLE t1 (b); +SELECT COUNT(*) FROM t1; +COUNT(*) +70 +LOAD DATA LOCAL INFILE 'FILE2' INTO TABLE t1 (b); +ERROR 42000: The used command is not allowed with this MySQL version +SELECT COUNT(*) FROM t1; +COUNT(*) +70 +SET @@global.local_infile=1; +DROP TABLE t1; + +* max_heap_table_size * +SET @restore_slave_max_heap_table_size=@@global.max_heap_table_size; +SET @@global.max_heap_table_size=16384; +SET @@session.max_heap_table_size=16384; +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10), c CHAR(254)) ENGINE=MEMORY; +SELECT COUNT(*)=2000 FROM t1; +COUNT(*)=2000 +1 +SELECT COUNT(*)=2000 FROM t1 WHERE b='master' GROUP BY b ORDER BY b; +COUNT(*)=2000 +1 +SELECT COUNT(*)<2000 AND COUNT(*)>0 FROM t1 WHERE b='slave' GROUP BY b ORDER BY b; +COUNT(*)<2000 AND COUNT(*)>0 +1 +SELECT COUNT(*)<2000 AND COUNT(*)>0 FROM t2 WHERE b='slave' GROUP BY b ORDER BY b; +COUNT(*)<2000 AND COUNT(*)>0 +1 +DROP TABLE IF EXISTS t1,t2; + +* storage_engine * +SET @restore_master_storage_engine=@@global.storage_engine; +SET @@global.storage_engine=InnoDB; +SET @@session.storage_engine=InnoDB; +SET @restore_slave_storage_engine=@@global.storage_engine; +SET @@global.storage_engine=Memory; +SET @@session.storage_engine=Memory; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)); +CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB; +CREATE TABLE t3 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(10) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) NOT NULL, + `b` varchar(10) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` varchar(10) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) NOT NULL, + `b` varchar(10) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` int(11) NOT NULL, + `b` varchar(10) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 +SET @@global.storage_engine=InnoDB; +SET @@session.storage_engine=InnoDB; +DROP TABLE IF EXISTS t1,t2,t3; + +* sql_mode * +SET @@global.sql_mode=ANSI; +SET @@session.sql_mode=ANSI; +SET @@global.sql_mode=TRADITIONAL; +SET @@session.sql_mode=TRADITIONAL; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10), c DATE); +INSERT INTO t1 VALUES (1, 'master', '0000-00-00'); +SELECT * FROM t1 ORDER BY a; +a b c +1 master 0000-00-00 +INSERT INTO t1 VALUES (1, 'slave', '0000-00-00'); +ERROR 22007: Incorrect date value: '0000-00-00' for column 'c' at row 1 +SELECT * FROM t1 ORDER BY a; +a b c +1 master 0000-00-00 +SET @@global.sql_mode=''; +SET @@session.sql_mode=''; +SET @@global.sql_mode=''; +SET @@session.sql_mode=''; +DROP TABLE t1; + +*** clean up *** +SET @@global.character_set_database=@restore_master_character_set_database; +SET @@global.collation_server=@restore_master_collation_server; +SET @@global.storage_engine=@restore_master_storage_engine; +SET @@global.character_set_database=@restore_slave_character_set_database; +SET @@global.collation_server=@restore_slave_collation_server; +SET @@global.max_heap_table_size=@restore_slave_max_heap_table_size; +SET @@global.storage_engine=@restore_slave_storage_engine; + +call mtr.add_suppression("The table 't[12]' is full"); diff --git a/mysql-test/suite/rpl/t/rpl_spec_variables-slave.opt b/mysql-test/suite/rpl/t/rpl_spec_variables-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_spec_variables-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/suite/rpl/t/rpl_spec_variables.test b/mysql-test/suite/rpl/t/rpl_spec_variables.test new file mode 100644 index 00000000000..a60738316c8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_spec_variables.test @@ -0,0 +1,306 @@ +############################################################# +# Author: Serge Kozlov +# Date: 07/01/2008 +# Purpose: Testing possible affects of some system dynamic +# variables to the replication. +# Scenario for each variable: +# 1) Set different values for master and slave +# 2) Create and replicate a data from master to slave +# 3) Check results on master and slave: changes on slave +# shouldn't be affected to replicated data. +############################################################# +--source include/have_innodb.inc +--source include/master-slave.inc +--echo + +# +# AUTO_INCREMENT +# +--echo * auto_increment_increment, auto_increment_offset * + +--connection master +SET @@global.auto_increment_increment=2; +SET @@session.auto_increment_increment=2; +SET @@global.auto_increment_offset=10; +SET @@session.auto_increment_offset=10; + +--connection slave +SET @@global.auto_increment_increment=3; +SET @@session.auto_increment_increment=3; +SET @@global.auto_increment_offset=20; +SET @@session.auto_increment_offset=20; + +--connection master +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +INSERT INTO t1 (b) VALUES ('master'); +INSERT INTO t1 (b) VALUES ('master'); +SELECT * FROM t1 ORDER BY a; + +--sync_slave_with_master +CREATE TABLE t2 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +INSERT INTO t1 (b) VALUES ('slave'); +INSERT INTO t1 (b) VALUES ('slave'); +INSERT INTO t2 (b) VALUES ('slave'); +INSERT INTO t2 (b) VALUES ('slave'); +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--connection master +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings +SET @@global.auto_increment_increment=1; +SET @@session.auto_increment_increment=1; +SET @@global.auto_increment_offset=1; +SET @@session.auto_increment_offset=1; + +--connection slave +SET @@global.auto_increment_increment=1; +SET @@session.auto_increment_increment=1; +SET @@global.auto_increment_offset=1; +SET @@session.auto_increment_offset=1; + +--connection slave +SET auto_increment_increment=1; +SET auto_increment_offset=1; +--echo + +# +# CHARACTER_SET_DATABASE, COLLATION_SERVER +# +--echo * character_set_database, collation_server * + +--connection master +SET @restore_master_character_set_database=@@global.character_set_database; +SET @restore_master_collation_server=@@global.collation_server; +SET @@global.character_set_database=latin1; +SET @@session.character_set_database=latin1; +SET @@global.collation_server=latin1_german1_ci; +SET @@session.collation_server=latin1_german1_ci; + +--connection slave +SET @restore_slave_character_set_database=@@global.character_set_database; +SET @restore_slave_collation_server=@@global.collation_server; +SET @@global.character_set_database=utf8; +SET @@session.character_set_database=utf8; +SET @@global.collation_server=utf8_bin; +SET @@session.collation_server=utf8_bin; + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +SHOW CREATE TABLE t1; + +--sync_slave_with_master +CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; + +SET @@global.collation_server=latin1_swedish_ci; +SET @@session.collation_server=latin1_swedish_ci; + +--connection master +SET @@global.collation_server=latin1_swedish_ci; +SET @@session.collation_server=latin1_swedish_ci; + +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings +--echo + +# +# DEFAULT_WEEK_FORMAT +# +--echo * default_week_format * + +--connection master +SET @@global.default_week_format=0; +SET @@session.default_week_format=0; + +--connection slave +SET @@global.default_week_format=1; +SET @@session.default_week_format=1; + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10), c INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 'master ', WEEK('2008-01-07')); +SELECT * FROM t1 ORDER BY a; + +--sync_slave_with_master +INSERT INTO t1 VALUES (2, 'slave ', WEEK('2008-01-07')); +SELECT * FROM t1 ORDER BY a; + +--connection master +DROP TABLE t1; + +--connection slave +SET @@global.default_week_format=0; +SET @@session.default_week_format=0; +--echo + +# +# LOCAL_INFILE +# +--echo * local_infile * + +--connection slave +SET @@global.local_infile=0; + +--connection master +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(20), c CHAR(254)) ENGINE=MyISAM; +--copy_file ./std_data/words.dat $MYSQLTEST_VARDIR/tmp/words.dat +--copy_file ./std_data/words2.dat $MYSQLTEST_VARDIR/tmp/words2.dat +--replace_regex /\'.+\'/'FILE'/ +--eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/tmp/words.dat' INTO TABLE t1 (b) +SELECT COUNT(*) FROM t1; +--sync_slave_with_master +--replace_regex /\'.+\'/'FILE2'/ +--error 1148 +--eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/tmp/words2.dat' INTO TABLE t1 (b) +SELECT COUNT(*) FROM t1; + +SET @@global.local_infile=1; + +--connection master +DROP TABLE t1; +--echo + +# +# MAX_HEAP_TABLE_SIZE +# +--echo * max_heap_table_size * + +--connection slave +SET @restore_slave_max_heap_table_size=@@global.max_heap_table_size; +SET @@global.max_heap_table_size=16384; +SET @@session.max_heap_table_size=16384; + +--connection master +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10), c CHAR(254)) ENGINE=MEMORY; +let $counter=2000; +--disable_query_log +while ($counter) { + INSERT INTO t1 (b,c) VALUES ('master', REPEAT('A', 254)); + dec $counter; +} +--enable_query_log +SELECT COUNT(*)=2000 FROM t1; + +--sync_slave_with_master +let $counter=2000; +--disable_query_log +while ($counter) { + --error 0,1114 + INSERT INTO t1 (b,c) VALUES ('slave', REPEAT('A', 254)); + dec $counter; +} +CREATE TABLE t2 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10), c CHAR(254)) ENGINE=MEMORY; +let $counter=2000; +--disable_query_log +while ($counter) { + --error 0,1114 + INSERT INTO t2 (b,c) VALUES ('slave', REPEAT('A', 254)); + dec $counter; +} +--enable_query_log +# We don't know how many memory used and can't check exact values so need to check following +# conditions +SELECT COUNT(*)=2000 FROM t1 WHERE b='master' GROUP BY b ORDER BY b; +SELECT COUNT(*)<2000 AND COUNT(*)>0 FROM t1 WHERE b='slave' GROUP BY b ORDER BY b; +SELECT COUNT(*)<2000 AND COUNT(*)>0 FROM t2 WHERE b='slave' GROUP BY b ORDER BY b; + +--connection master +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings +--echo + +# +# STORAGE_ENGINE +# +--echo * storage_engine * + +--connection master +SET @restore_master_storage_engine=@@global.storage_engine; +SET @@global.storage_engine=InnoDB; +SET @@session.storage_engine=InnoDB; + +--connection slave +SET @restore_slave_storage_engine=@@global.storage_engine; +SET @@global.storage_engine=Memory; +SET @@session.storage_engine=Memory; + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)); +CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB; + +--sync_slave_with_master +CREATE TABLE t3 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)); + +--connection master +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; + +--connection slave +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; +SHOW CREATE TABLE t3; + +SET @@global.storage_engine=InnoDB; +SET @@session.storage_engine=InnoDB; + +--connection master +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3; +--enable_warnings +--echo + +# +# SQL_MODE +# +--echo * sql_mode * + +--connection master +SET @@global.sql_mode=ANSI; +SET @@session.sql_mode=ANSI; + +--connection slave +SET @@global.sql_mode=TRADITIONAL; +SET @@session.sql_mode=TRADITIONAL; + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10), c DATE); +INSERT INTO t1 VALUES (1, 'master', '0000-00-00'); +SELECT * FROM t1 ORDER BY a; + +--sync_slave_with_master +--error 1292 +INSERT INTO t1 VALUES (1, 'slave', '0000-00-00'); +SELECT * FROM t1 ORDER BY a; +SET @@global.sql_mode=''; +SET @@session.sql_mode=''; + +--connection master +SET @@global.sql_mode=''; +SET @@session.sql_mode=''; +DROP TABLE t1; +--echo + + +# Clean up +--echo *** clean up *** +--connection master +SET @@global.character_set_database=@restore_master_character_set_database; +SET @@global.collation_server=@restore_master_collation_server; +SET @@global.storage_engine=@restore_master_storage_engine; +--sync_slave_with_master +SET @@global.character_set_database=@restore_slave_character_set_database; +SET @@global.collation_server=@restore_slave_collation_server; +SET @@global.max_heap_table_size=@restore_slave_max_heap_table_size; +SET @@global.storage_engine=@restore_slave_storage_engine; + +# Put at the end since the test otherwise emptied the table. + +--echo +call mtr.add_suppression("The table 't[12]' is full"); + +# End of 5.1 test From 8bc5d18bd8960c78faaa7feffaf39bcee3416d77 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Sat, 3 Oct 2009 23:47:25 +0400 Subject: [PATCH 076/274] Fix default.conf. --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index d771989c69a..7fcaaa9aa09 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-next-mr-wtf" +tree_name = "mysql-next-mr" From 5b1339390836f6f961e6903e44648ee95230452a Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Sat, 3 Oct 2009 23:59:28 +0400 Subject: [PATCH 077/274] Fix default.conf. --- .bzr-mysql/default.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index 7fcaaa9aa09..771201a109b 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-next-mr" +tree_name = "mysql-5.4.5-next-mr" From 01072e22fe7cc5e7a53e9ea0a065ba22027d52bf Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Mon, 5 Oct 2009 16:10:18 +0200 Subject: [PATCH 078/274] BUG#47776, Fixed character set handling, used wrong length, eventually also found that didn't need to convert to my_strnxfrm-format for column list partitioned tables, also column list partitioned tables can use multi-byte character sets in partition fields as well as where strxfrm multiplies the number of bytes in the string --- mysql-test/r/partition_innodb.result | 24 ++++++++++++++++++++ mysql-test/t/partition_innodb.test | 30 ++++++++++++++++++++++++ sql/sql_partition.cc | 34 +++++++++++++++++----------- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index af277e5ce40..fb991ef5fcc 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -1,4 +1,28 @@ drop table if exists t1; +create table t1 (a varchar(5)) +engine=memory +partition by range column_list(a) +( partition p0 values less than (column_list('m')), +partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; +create table t1 (a varchar(5)) +engine=myisam +partition by range column_list(a) +( partition p0 values less than (column_list('m')), +partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; +create table t1 (a varchar(5)) +engine=innodb +partition by range column_list(a) +( partition p0 values less than (column_list('m')), +partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; CREATE TABLE t1 (id INT PRIMARY KEY, data INT) ENGINE = InnoDB PARTITION BY RANGE(id) ( PARTITION p0 VALUES LESS THAN (5), diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index c6bf0af0b6f..a8758525342 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -5,6 +5,36 @@ drop table if exists t1; --enable_warnings +# +# BUG#47776, Failed to update for MEMORY engine, crash for InnoDB and success for MyISAM +# +create table t1 (a varchar(5)) +engine=memory +partition by range column_list(a) +( partition p0 values less than (column_list('m')), + partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; + +create table t1 (a varchar(5)) +engine=myisam +partition by range column_list(a) +( partition p0 values less than (column_list('m')), + partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; + +create table t1 (a varchar(5)) +engine=innodb +partition by range column_list(a) +( partition p0 values less than (column_list('m')), + partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; + # # Bug#40595: Non-matching rows not released with READ-COMMITTED on tables # with partitions diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 898cf8f07cd..5e7fdb6c981 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1404,15 +1404,21 @@ static void set_up_partition_func_pointers(partition_info *part_info) if (part_info->is_sub_partitioned()) { DBUG_ASSERT(part_info->get_part_partition_id); - part_info->get_part_partition_id_charset= - part_info->get_part_partition_id; - part_info->get_part_partition_id= get_part_id_charset_func_part; + if (!part_info->column_list) + { + part_info->get_part_partition_id= + part_info->get_part_partition_id_charset; + part_info->get_part_partition_id= get_part_id_charset_func_part; + } } else { DBUG_ASSERT(part_info->get_partition_id); - part_info->get_part_partition_id_charset= part_info->get_partition_id; - part_info->get_partition_id= get_part_id_charset_func_part; + if (!part_info->column_list) + { + part_info->get_part_partition_id_charset= part_info->get_partition_id; + part_info->get_part_partition_id= get_part_id_charset_func_part; + } } } if (part_info->subpart_charset_field_array) @@ -1715,7 +1721,8 @@ bool fix_partition_func(THD *thd, TABLE *table, } if (((part_info->part_type != HASH_PARTITION || part_info->list_of_part_fields == FALSE) && - check_part_func_fields(part_info->part_field_array, TRUE)) || + (!part_info->column_list && + check_part_func_fields(part_info->part_field_array, TRUE))) || (part_info->list_of_part_fields == FALSE && part_info->is_sub_partitioned() && check_part_func_fields(part_info->subpart_field_array, TRUE))) @@ -2603,7 +2610,8 @@ static void copy_to_part_field_buffers(Field **ptr, if (!field->maybe_null() || !field->is_null()) { CHARSET_INFO *cs= ((Field_str*)field)->charset(); - uint len= field->pack_length(); + uint max_len= field->pack_length(); + uint data_len= field->data_length(); uchar *field_buf= *field_bufs; /* We only use the field buffer for VARCHAR and CHAR strings @@ -2615,17 +2623,17 @@ static void copy_to_part_field_buffers(Field **ptr, if (field->type() == MYSQL_TYPE_VARCHAR) { uint len_bytes= ((Field_varstring*)field)->length_bytes; - my_strnxfrm(cs, field_buf + len_bytes, (len - len_bytes), - field->ptr + len_bytes, field->field_length); + my_strnxfrm(cs, field_buf + len_bytes, max_len, + field->ptr + len_bytes, data_len); if (len_bytes == 1) - *field_buf= (uchar) field->field_length; + *field_buf= (uchar) data_len; else - int2store(field_buf, field->field_length); + int2store(field_buf, data_len); } else { - my_strnxfrm(cs, field_buf, len, - field->ptr, field->field_length); + my_strnxfrm(cs, field_buf, max_len, + field->ptr, max_len); } field->ptr= field_buf; } From 42e807783465ea9b3bc60746baafbb07c1462b68 Mon Sep 17 00:00:00 2001 From: Guilhem Bichot Date: Mon, 5 Oct 2009 16:22:48 +0200 Subject: [PATCH 079/274] Port of fix for BUG#42893 "main.information_schema times out sporadically" (from revision konstantin@mysql.com-20080627154042-923m6lzk7z77lrgj ). This moves the slow part (10 seconds over 13) into a separate big test. --- mysql-test/r/information_schema-big.result | 93 ++++++++++++++++++++++ mysql-test/r/information_schema.result | 88 -------------------- mysql-test/t/information_schema-big.test | 48 +++++++++++ mysql-test/t/information_schema.test | 35 -------- 4 files changed, 141 insertions(+), 123 deletions(-) create mode 100644 mysql-test/r/information_schema-big.result create mode 100644 mysql-test/t/information_schema-big.test diff --git a/mysql-test/r/information_schema-big.result b/mysql-test/r/information_schema-big.result new file mode 100644 index 00000000000..248b8d606dc --- /dev/null +++ b/mysql-test/r/information_schema-big.result @@ -0,0 +1,93 @@ +DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5; +DROP VIEW IF EXISTS v1; +# +# Bug#18925: subqueries with MIN/MAX functions on INFORMARTION_SCHEMA +# +SELECT t.table_name, c1.column_name +FROM information_schema.tables t +INNER JOIN +information_schema.columns c1 +ON t.table_schema = c1.table_schema AND +t.table_name = c1.table_name +WHERE t.table_schema = 'information_schema' AND +c1.ordinal_position = +( SELECT COALESCE(MIN(c2.ordinal_position),1) +FROM information_schema.columns c2 +WHERE c2.table_schema = t.table_schema AND +c2.table_name = t.table_name AND +c2.column_name LIKE '%SCHEMA%' + ) +AND t.table_name NOT LIKE 'innodb%'; +table_name column_name +CHARACTER_SETS CHARACTER_SET_NAME +COLLATIONS COLLATION_NAME +COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME +COLUMNS TABLE_SCHEMA +COLUMN_PRIVILEGES TABLE_SCHEMA +ENGINES ENGINE +EVENTS EVENT_SCHEMA +FILES TABLE_SCHEMA +GLOBAL_STATUS VARIABLE_NAME +GLOBAL_VARIABLES VARIABLE_NAME +KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +PARTITIONS TABLE_SCHEMA +PLUGINS PLUGIN_NAME +PROCESSLIST ID +PROFILING QUERY_ID +REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA +ROUTINES ROUTINE_SCHEMA +SCHEMATA SCHEMA_NAME +SCHEMA_PRIVILEGES TABLE_SCHEMA +SESSION_STATUS VARIABLE_NAME +SESSION_VARIABLES VARIABLE_NAME +STATISTICS TABLE_SCHEMA +TABLES TABLE_SCHEMA +TABLE_CONSTRAINTS CONSTRAINT_SCHEMA +TABLE_PRIVILEGES TABLE_SCHEMA +TRIGGERS TRIGGER_SCHEMA +USER_PRIVILEGES GRANTEE +VIEWS TABLE_SCHEMA +SELECT t.table_name, c1.column_name +FROM information_schema.tables t +INNER JOIN +information_schema.columns c1 +ON t.table_schema = c1.table_schema AND +t.table_name = c1.table_name +WHERE t.table_schema = 'information_schema' AND +c1.ordinal_position = +( SELECT COALESCE(MIN(c2.ordinal_position),1) +FROM information_schema.columns c2 +WHERE c2.table_schema = 'information_schema' AND +c2.table_name = t.table_name AND +c2.column_name LIKE '%SCHEMA%' + ) +AND t.table_name NOT LIKE 'innodb%'; +table_name column_name +CHARACTER_SETS CHARACTER_SET_NAME +COLLATIONS COLLATION_NAME +COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME +COLUMNS TABLE_SCHEMA +COLUMN_PRIVILEGES TABLE_SCHEMA +ENGINES ENGINE +EVENTS EVENT_SCHEMA +FILES TABLE_SCHEMA +GLOBAL_STATUS VARIABLE_NAME +GLOBAL_VARIABLES VARIABLE_NAME +KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +PARTITIONS TABLE_SCHEMA +PLUGINS PLUGIN_NAME +PROCESSLIST ID +PROFILING QUERY_ID +REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA +ROUTINES ROUTINE_SCHEMA +SCHEMATA SCHEMA_NAME +SCHEMA_PRIVILEGES TABLE_SCHEMA +SESSION_STATUS VARIABLE_NAME +SESSION_VARIABLES VARIABLE_NAME +STATISTICS TABLE_SCHEMA +TABLES TABLE_SCHEMA +TABLE_CONSTRAINTS CONSTRAINT_SCHEMA +TABLE_PRIVILEGES TABLE_SCHEMA +TRIGGERS TRIGGER_SCHEMA +USER_PRIVILEGES GRANTEE +VIEWS TABLE_SCHEMA diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index ffa9b596d2f..9a66c809226 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1226,94 +1226,6 @@ f1() DROP FUNCTION f1; DROP PROCEDURE p1; DROP USER mysql_bug20230@localhost; -SELECT t.table_name, c1.column_name -FROM information_schema.tables t -INNER JOIN -information_schema.columns c1 -ON t.table_schema = c1.table_schema AND -t.table_name = c1.table_name -WHERE t.table_schema = 'information_schema' AND -c1.ordinal_position = -( SELECT COALESCE(MIN(c2.ordinal_position),1) -FROM information_schema.columns c2 -WHERE c2.table_schema = t.table_schema AND -c2.table_name = t.table_name AND -c2.column_name LIKE '%SCHEMA%' - ) -AND t.table_name not like 'innodb_%'; -table_name column_name -CHARACTER_SETS CHARACTER_SET_NAME -COLLATIONS COLLATION_NAME -COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME -COLUMNS TABLE_SCHEMA -COLUMN_PRIVILEGES TABLE_SCHEMA -ENGINES ENGINE -EVENTS EVENT_SCHEMA -FILES TABLE_SCHEMA -GLOBAL_STATUS VARIABLE_NAME -GLOBAL_VARIABLES VARIABLE_NAME -KEY_COLUMN_USAGE CONSTRAINT_SCHEMA -PARTITIONS TABLE_SCHEMA -PLUGINS PLUGIN_NAME -PROCESSLIST ID -PROFILING QUERY_ID -REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA -ROUTINES ROUTINE_SCHEMA -SCHEMATA SCHEMA_NAME -SCHEMA_PRIVILEGES TABLE_SCHEMA -SESSION_STATUS VARIABLE_NAME -SESSION_VARIABLES VARIABLE_NAME -STATISTICS TABLE_SCHEMA -TABLES TABLE_SCHEMA -TABLE_CONSTRAINTS CONSTRAINT_SCHEMA -TABLE_PRIVILEGES TABLE_SCHEMA -TRIGGERS TRIGGER_SCHEMA -USER_PRIVILEGES GRANTEE -VIEWS TABLE_SCHEMA -SELECT t.table_name, c1.column_name -FROM information_schema.tables t -INNER JOIN -information_schema.columns c1 -ON t.table_schema = c1.table_schema AND -t.table_name = c1.table_name -WHERE t.table_schema = 'information_schema' AND -c1.ordinal_position = -( SELECT COALESCE(MIN(c2.ordinal_position),1) -FROM information_schema.columns c2 -WHERE c2.table_schema = 'information_schema' AND -c2.table_name = t.table_name AND -c2.column_name LIKE '%SCHEMA%' - ) -AND t.table_name not like 'innodb_%'; -table_name column_name -CHARACTER_SETS CHARACTER_SET_NAME -COLLATIONS COLLATION_NAME -COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME -COLUMNS TABLE_SCHEMA -COLUMN_PRIVILEGES TABLE_SCHEMA -ENGINES ENGINE -EVENTS EVENT_SCHEMA -FILES TABLE_SCHEMA -GLOBAL_STATUS VARIABLE_NAME -GLOBAL_VARIABLES VARIABLE_NAME -KEY_COLUMN_USAGE CONSTRAINT_SCHEMA -PARTITIONS TABLE_SCHEMA -PLUGINS PLUGIN_NAME -PROCESSLIST ID -PROFILING QUERY_ID -REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA -ROUTINES ROUTINE_SCHEMA -SCHEMATA SCHEMA_NAME -SCHEMA_PRIVILEGES TABLE_SCHEMA -SESSION_STATUS VARIABLE_NAME -SESSION_VARIABLES VARIABLE_NAME -STATISTICS TABLE_SCHEMA -TABLES TABLE_SCHEMA -TABLE_CONSTRAINTS CONSTRAINT_SCHEMA -TABLE_PRIVILEGES TABLE_SCHEMA -TRIGGERS TRIGGER_SCHEMA -USER_PRIVILEGES GRANTEE -VIEWS TABLE_SCHEMA SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test'); MAX(table_name) VIEWS diff --git a/mysql-test/t/information_schema-big.test b/mysql-test/t/information_schema-big.test new file mode 100644 index 00000000000..c9cd65f0851 --- /dev/null +++ b/mysql-test/t/information_schema-big.test @@ -0,0 +1,48 @@ +# This test uses grants, which can't get tested for embedded server +-- source include/big_test.inc +-- source include/not_embedded.inc + +# check that CSV engine was compiled in, as the result of the test depends +# on the presence of the log tables (which are CSV-based). +--source include/have_csv.inc + +--disable_warnings +DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5; +DROP VIEW IF EXISTS v1; +--enable_warnings + + +--echo # +--echo # Bug#18925: subqueries with MIN/MAX functions on INFORMARTION_SCHEMA +--echo # + +SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN + information_schema.columns c1 + ON t.table_schema = c1.table_schema AND + t.table_name = c1.table_name + WHERE t.table_schema = 'information_schema' AND + c1.ordinal_position = + ( SELECT COALESCE(MIN(c2.ordinal_position),1) + FROM information_schema.columns c2 + WHERE c2.table_schema = t.table_schema AND + c2.table_name = t.table_name AND + c2.column_name LIKE '%SCHEMA%' + ) + AND t.table_name NOT LIKE 'innodb%'; +SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN + information_schema.columns c1 + ON t.table_schema = c1.table_schema AND + t.table_name = c1.table_name + WHERE t.table_schema = 'information_schema' AND + c1.ordinal_position = + ( SELECT COALESCE(MIN(c2.ordinal_position),1) + FROM information_schema.columns c2 + WHERE c2.table_schema = 'information_schema' AND + c2.table_name = t.table_name AND + c2.column_name LIKE '%SCHEMA%' + ) + AND t.table_name NOT LIKE 'innodb%'; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 6060c78f791..b590ec306d6 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -913,41 +913,6 @@ DROP FUNCTION f1; DROP PROCEDURE p1; DROP USER mysql_bug20230@localhost; -# -# Bug#18925 subqueries with MIN/MAX functions on INFORMARTION_SCHEMA -# - -SELECT t.table_name, c1.column_name - FROM information_schema.tables t - INNER JOIN - information_schema.columns c1 - ON t.table_schema = c1.table_schema AND - t.table_name = c1.table_name - WHERE t.table_schema = 'information_schema' AND - c1.ordinal_position = - ( SELECT COALESCE(MIN(c2.ordinal_position),1) - FROM information_schema.columns c2 - WHERE c2.table_schema = t.table_schema AND - c2.table_name = t.table_name AND - c2.column_name LIKE '%SCHEMA%' - ) - AND t.table_name not like 'innodb_%'; -SELECT t.table_name, c1.column_name - FROM information_schema.tables t - INNER JOIN - information_schema.columns c1 - ON t.table_schema = c1.table_schema AND - t.table_name = c1.table_name - WHERE t.table_schema = 'information_schema' AND - c1.ordinal_position = - ( SELECT COALESCE(MIN(c2.ordinal_position),1) - FROM information_schema.columns c2 - WHERE c2.table_schema = 'information_schema' AND - c2.table_name = t.table_name AND - c2.column_name LIKE '%SCHEMA%' - ) - AND t.table_name not like 'innodb_%'; - # # Bug#2123 query with a simple non-correlated subquery over # INFORMARTION_SCHEMA.TABLES From 636ea6a1c464b247a3665bebac7bf28495ac087a Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 5 Oct 2009 20:06:04 +0500 Subject: [PATCH 080/274] WL#4584 Internationalized number format @ mysql-test/r/func_str.result Adding tests @ mysql-test/t/func_str.test Adding tests @ mysql-test/t/variables.test Fixing error number @ sql/item_create.cc Allowing 2 and 3 arguments to format() @ sql/item_strfunc.cc Adding new formatting code. @ sql/item_strfunc.h Adding new contructors and "locale" member @ sql/mysql_priv.h Adding number formatting members into MY_LOCALE @ sql/sql_locale.cc Adding number formatting data into locale constants @ sql/set_var.cc Using new error message @ sql/share/errmgs.txt Adding new error message --- mysql-test/r/func_str.result | 130 +++++++++ mysql-test/t/func_str.test | 42 +++ mysql-test/t/variables.test | 6 +- sql/item_create.cc | 33 ++- sql/item_strfunc.cc | 90 ++++-- sql/item_strfunc.h | 7 +- sql/mysql_priv.h | 12 +- sql/set_var.cc | 5 +- sql/share/errmsg.txt | 2 + sql/sql_locale.cc | 547 ++++++++++++++++++++++++++++------- 10 files changed, 725 insertions(+), 149 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index c87879e13b5..39d11aa3e2c 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2558,3 +2558,133 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 2 Using join buffer 2 DERIVED t1 ALL NULL NULL NULL NULL 2 drop table t1; +Start of 5.4 tests +SELECT format(12345678901234567890.123, 3); +format(12345678901234567890.123, 3) +12,345,678,901,234,567,890.123 +SELECT format(12345678901234567890.123, 3, NULL); +format(12345678901234567890.123, 3, NULL) +12,345,678,901,234,567,890.123 +Warnings: +Warning 1647 Unknown locale: 'NULL' +SELECT format(12345678901234567890.123, 3, 'ar_AE'); +format(12345678901234567890.123, 3, 'ar_AE') +12,345,678,901,234,567,890.123 +SELECT format(12345678901234567890.123, 3, 'ar_SA'); +format(12345678901234567890.123, 3, 'ar_SA') +12345678901234567890.123 +SELECT format(12345678901234567890.123, 3, 'be_BY'); +format(12345678901234567890.123, 3, 'be_BY') +12.345.678.901.234.567.890,123 +SELECT format(12345678901234567890.123, 3, 'de_DE'); +format(12345678901234567890.123, 3, 'de_DE') +12.345.678.901.234.567.890,123 +SELECT format(12345678901234567890.123, 3, 'en_IN'); +format(12345678901234567890.123, 3, 'en_IN') +1,23,45,67,89,01,23,45,67,890.123 +SELECT format(12345678901234567890.123, 3, 'en_US'); +format(12345678901234567890.123, 3, 'en_US') +12,345,678,901,234,567,890.123 +SELECT format(12345678901234567890.123, 3, 'it_CH'); +format(12345678901234567890.123, 3, 'it_CH') +12'345'678'901'234'567'890,123 +SELECT format(12345678901234567890.123, 3, 'ru_RU'); +format(12345678901234567890.123, 3, 'ru_RU') +12 345 678 901 234 567 890,123 +SELECT format(12345678901234567890.123, 3, 'ta_IN'); +format(12345678901234567890.123, 3, 'ta_IN') +1,23,45,67,89,01,23,45,67,890.123 +CREATE TABLE t1 (fmt CHAR(5) NOT NULL); +INSERT INTO t1 VALUES ('ar_AE'); +INSERT INTO t1 VALUES ('ar_SA'); +INSERT INTO t1 VALUES ('be_BY'); +INSERT INTO t1 VALUES ('de_DE'); +INSERT INTO t1 VALUES ('en_IN'); +INSERT INTO t1 VALUES ('en_US'); +INSERT INTO t1 VALUES ('it_CH'); +INSERT INTO t1 VALUES ('ru_RU'); +INSERT INTO t1 VALUES ('ta_IN'); +SELECT fmt, format(12345678901234567890.123, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(12345678901234567890.123, 3, fmt) +ar_AE 12,345,678,901,234,567,890.123 +ar_SA 12345678901234567890.123 +be_BY 12.345.678.901.234.567.890,123 +de_DE 12.345.678.901.234.567.890,123 +en_IN 1,23,45,67,89,01,23,45,67,890.123 +en_US 12,345,678,901,234,567,890.123 +it_CH 12'345'678'901'234'567'890,123 +ru_RU 12 345 678 901 234 567 890,123 +ta_IN 1,23,45,67,89,01,23,45,67,890.123 +SELECT fmt, format(12345678901234567890.123, 0, fmt) FROM t1 ORDER BY fmt; +fmt format(12345678901234567890.123, 0, fmt) +ar_AE 12,345,678,901,234,567,890 +ar_SA 12345678901234567890 +be_BY 12.345.678.901.234.567.890 +de_DE 12.345.678.901.234.567.890 +en_IN 1,23,45,67,89,01,23,45,67,890 +en_US 12,345,678,901,234,567,890 +it_CH 12'345'678'901'234'567'890 +ru_RU 12 345 678 901 234 567 890 +ta_IN 1,23,45,67,89,01,23,45,67,890 +SELECT fmt, format(12345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(12345678901234567890, 3, fmt) +ar_AE 12,345,678,901,234,567,890.000 +ar_SA 12345678901234567890.000 +be_BY 12.345.678.901.234.567.890,000 +de_DE 12.345.678.901.234.567.890,000 +en_IN 1,23,45,67,89,01,23,45,67,890.000 +en_US 12,345,678,901,234,567,890.000 +it_CH 12'345'678'901'234'567'890,000 +ru_RU 12 345 678 901 234 567 890,000 +ta_IN 1,23,45,67,89,01,23,45,67,890.000 +SELECT fmt, format(-12345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(-12345678901234567890, 3, fmt) +ar_AE -12,345,678,901,234,567,890.000 +ar_SA -12345678901234567890.000 +be_BY -12.345.678.901.234.567.890,000 +de_DE -12.345.678.901.234.567.890,000 +en_IN -1,23,45,67,89,01,23,45,67,890.000 +en_US -12,345,678,901,234,567,890.000 +it_CH -12'345'678'901'234'567'890,000 +ru_RU -12 345 678 901 234 567 890,000 +ta_IN -1,23,45,67,89,01,23,45,67,890.000 +SELECT fmt, format(-02345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(-02345678901234567890, 3, fmt) +ar_AE -2,345,678,901,234,567,890.000 +ar_SA -2345678901234567890.000 +be_BY -2.345.678.901.234.567.890,000 +de_DE -2.345.678.901.234.567.890,000 +en_IN -23,45,67,89,01,23,45,67,890.000 +en_US -2,345,678,901,234,567,890.000 +it_CH -2'345'678'901'234'567'890,000 +ru_RU -2 345 678 901 234 567 890,000 +ta_IN -23,45,67,89,01,23,45,67,890.000 +SELECT fmt, format(-00345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(-00345678901234567890, 3, fmt) +ar_AE -345,678,901,234,567,890.000 +ar_SA -345678901234567890.000 +be_BY -345.678.901.234.567.890,000 +de_DE -345.678.901.234.567.890,000 +en_IN -3,45,67,89,01,23,45,67,890.000 +en_US -345,678,901,234,567,890.000 +it_CH -345'678'901'234'567'890,000 +ru_RU -345 678 901 234 567 890,000 +ta_IN -3,45,67,89,01,23,45,67,890.000 +SELECT fmt, format(-00045678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +fmt format(-00045678901234567890, 3, fmt) +ar_AE -45,678,901,234,567,890.000 +ar_SA -45678901234567890.000 +be_BY -45.678.901.234.567.890,000 +de_DE -45.678.901.234.567.890,000 +en_IN -45,67,89,01,23,45,67,890.000 +en_US -45,678,901,234,567,890.000 +it_CH -45'678'901'234'567'890,000 +ru_RU -45 678 901 234 567 890,000 +ta_IN -45,67,89,01,23,45,67,890.000 +DROP TABLE t1; +SELECT format(123, 1, 'Non-existent-locale'); +format(123, 1, 'Non-existent-locale') +123.0 +Warnings: +Warning 1647 Unknown locale: 'Non-existent-locale' +End of 5.4 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 66b9eabd385..032c9ade643 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1318,3 +1318,45 @@ insert into t1 values (-1),(null); explain select 1 as a from t1,(select decode(f1,f1) as b from t1) a; explain select 1 as a from t1,(select encode(f1,f1) as b from t1) a; drop table t1; + + + +--echo Start of 5.4 tests +# +# WL#4584 Internationalized number format +# +SELECT format(12345678901234567890.123, 3); +SELECT format(12345678901234567890.123, 3, NULL); +SELECT format(12345678901234567890.123, 3, 'ar_AE'); +SELECT format(12345678901234567890.123, 3, 'ar_SA'); +SELECT format(12345678901234567890.123, 3, 'be_BY'); +SELECT format(12345678901234567890.123, 3, 'de_DE'); +SELECT format(12345678901234567890.123, 3, 'en_IN'); +SELECT format(12345678901234567890.123, 3, 'en_US'); +SELECT format(12345678901234567890.123, 3, 'it_CH'); +SELECT format(12345678901234567890.123, 3, 'ru_RU'); +SELECT format(12345678901234567890.123, 3, 'ta_IN'); + +CREATE TABLE t1 (fmt CHAR(5) NOT NULL); +INSERT INTO t1 VALUES ('ar_AE'); +INSERT INTO t1 VALUES ('ar_SA'); +INSERT INTO t1 VALUES ('be_BY'); +INSERT INTO t1 VALUES ('de_DE'); +INSERT INTO t1 VALUES ('en_IN'); +INSERT INTO t1 VALUES ('en_US'); +INSERT INTO t1 VALUES ('it_CH'); +INSERT INTO t1 VALUES ('ru_RU'); +INSERT INTO t1 VALUES ('ta_IN'); +SELECT fmt, format(12345678901234567890.123, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(12345678901234567890.123, 0, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(12345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(-12345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(-02345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(-00345678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +SELECT fmt, format(-00045678901234567890, 3, fmt) FROM t1 ORDER BY fmt; +DROP TABLE t1; + +SELECT format(123, 1, 'Non-existent-locale'); + +--echo End of 5.4 tests + diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 1580d7f36d7..a98163e026c 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -559,7 +559,7 @@ select @@lc_time_names; --echo *** LC_TIME_NAMES: testing with string expressions set lc_time_names=concat('de','_','DE'); select @@lc_time_names; ---error ER_UNKNOWN_ERROR +--error ER_UNKNOWN_LOCALE set lc_time_names=concat('de','+','DE'); select @@lc_time_names; --echo LC_TIME_NAMES: testing with numeric expressions @@ -572,14 +572,14 @@ set lc_time_names=en_US; --echo LC_TIME_NAMES: testing NULL and a negative number: --error ER_WRONG_VALUE_FOR_VAR set lc_time_names=NULL; ---error ER_UNKNOWN_ERROR +--error ER_UNKNOWN_LOCALE set lc_time_names=-1; select @@lc_time_names; --echo LC_TIME_NAMES: testing locale with the last ID: set lc_time_names=108; select @@lc_time_names; --echo LC_TIME_NAMES: testing a number beyond the valid ID range: ---error ER_UNKNOWN_ERROR +--error ER_UNKNOWN_LOCALE set lc_time_names=109; select @@lc_time_names; --echo LC_TIME_NAMES: testing that 0 is en_US: diff --git a/sql/item_create.cc b/sql/item_create.cc index 7991d9adf82..2f80d16b928 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -927,10 +927,10 @@ protected: }; -class Create_func_format : public Create_func_arg2 +class Create_func_format : public Create_native_func { public: - virtual Item *create(THD *thd, Item *arg1, Item *arg2); + virtual Item *create_native(THD *thd, LEX_STRING name, List *item_list); static Create_func_format s_singleton; @@ -3352,9 +3352,34 @@ Create_func_floor::create(THD *thd, Item *arg1) Create_func_format Create_func_format::s_singleton; Item* -Create_func_format::create(THD *thd, Item *arg1, Item *arg2) +Create_func_format::create_native(THD *thd, LEX_STRING name, + List *item_list) { - return new (thd->mem_root) Item_func_format(arg1, arg2); + Item *func= NULL; + int arg_count= item_list ? item_list->elements : 0; + + switch (arg_count) { + case 2: + { + Item *param_1= item_list->pop(); + Item *param_2= item_list->pop(); + func= new (thd->mem_root) Item_func_format(param_1, param_2); + break; + } + case 3: + { + Item *param_1= item_list->pop(); + Item *param_2= item_list->pop(); + Item *param_3= item_list->pop(); + func= new (thd->mem_root) Item_func_format(param_1, param_2, param_3); + break; + } + default: + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); + break; + } + + return func; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7a4ffedac10..d4ef55e5609 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2040,9 +2040,22 @@ String *Item_func_soundex::val_str(String *str) const int FORMAT_MAX_DECIMALS= 30; -Item_func_format::Item_func_format(Item *org, Item *dec) -: Item_str_func(org, dec) + +MY_LOCALE *Item_func_format::get_locale(Item *item) { + DBUG_ASSERT(arg_count == 3); + String tmp, *locale_name= args[2]->val_str(&tmp); + MY_LOCALE *lc; + if (!locale_name || + !(lc= my_locale_by_name(locale_name->c_ptr_safe()))) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_UNKNOWN_LOCALE, + ER(ER_UNKNOWN_LOCALE), + locale_name ? locale_name->c_ptr_safe() : "NULL"); + lc= &my_locale_en_US; + } + return lc; } void Item_func_format::fix_length_and_dec() @@ -2052,6 +2065,10 @@ void Item_func_format::fix_length_and_dec() collation.set(default_charset()); max_length= (char_length + max_sep_count + decimals) * collation.collation->mbmaxlen; + if (arg_count == 3) + locale= args[2]->basic_const_item() ? get_locale(args[2]) : NULL; + else + locale= &my_locale_en_US; /* Two arguments */ } @@ -2063,13 +2080,12 @@ void Item_func_format::fix_length_and_dec() String *Item_func_format::val_str(String *str) { - uint32 length; uint32 str_length; /* Number of decimal digits */ int dec; /* Number of characters used to represent the decimals, including '.' */ uint32 dec_length; - int diff; + MY_LOCALE *lc; DBUG_ASSERT(fixed == 1); dec= (int) args[1]->val_int(); @@ -2079,6 +2095,8 @@ String *Item_func_format::val_str(String *str) return NULL; } + lc= locale ? locale : get_locale(args[2]); + dec= set_zone(dec, 0, FORMAT_MAX_DECIMALS); dec_length= dec ? dec+1 : 0; null_value=0; @@ -2093,8 +2111,6 @@ String *Item_func_format::val_str(String *str) my_decimal_round(E_DEC_FATAL_ERROR, res, dec, false, &rnd_dec); my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str); str_length= str->length(); - if (rnd_dec.sign()) - str_length--; } else { @@ -2107,31 +2123,51 @@ String *Item_func_format::val_str(String *str) if (isnan(nr)) return str; str_length=str->length(); - if (nr < 0) - str_length--; // Don't count sign } - /* We need this test to handle 'nan' values */ - if (str_length >= dec_length+4) + /* We need this test to handle 'nan' and short values */ + if (lc->grouping[0] > 0 && + str_length >= dec_length + 1 + lc->grouping[0]) { - char *tmp,*pos; - length= str->length()+(diff=((int)(str_length- dec_length-1))/3); - str= copy_if_not_alloced(&tmp_str,str,length); - str->length(length); - tmp= (char*) str->ptr()+length - dec_length-1; - for (pos= (char*) str->ptr()+length-1; pos != tmp; pos--) - pos[0]= pos[-diff]; - while (diff) + char buf[DECIMAL_MAX_STR_LENGTH * 2]; /* 2 - in the worst case when grouping=1 */ + int count; + const char *grouping= lc->grouping; + char sign_length= *str->ptr() == '-' ? 1 : 0; + const char *src= str->ptr() + str_length - dec_length - 1; + const char *src_begin= str->ptr() + sign_length; + char *dst= buf + sizeof(buf); + + /* Put the fractional part */ + if (dec) { - *pos= *(pos - diff); - pos--; - *pos= *(pos - diff); - pos--; - *pos= *(pos - diff); - pos--; - pos[0]=','; - pos--; - diff--; + dst-= (dec + 1); + *dst= lc->decimal_point; + memcpy(dst + 1, src + 2, dec); } + + /* Put the integer part with grouping */ + for (count= *grouping; src >= src_begin; count--) + { + /* + When *grouping==0x80 (which means "end of grouping") + count will be initialized to -1 and + we'll never get into this "if" anymore. + */ + if (!count) + { + *--dst= lc->thousand_sep; + if (grouping[1]) + grouping++; + count= *grouping; + } + DBUG_ASSERT(dst > buf); + *--dst= *src--; + } + + if (sign_length) /* Put '-' */ + *--dst= *str->ptr(); + + /* Put the rest of the integer part without grouping */ + str->copy(dst, buf + sizeof(buf) - dst, &my_charset_latin1); } return str; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 2cdb45100ae..87d8c7bd438 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -498,8 +498,13 @@ public: class Item_func_format :public Item_str_func { String tmp_str; + MY_LOCALE *locale; public: - Item_func_format(Item *org, Item *dec); + Item_func_format(Item *org, Item *dec): Item_str_func(org, dec) {} + Item_func_format(Item *org, Item *dec, Item *lang): + Item_str_func(org, dec, lang) {} + + MY_LOCALE *get_locale(Item *item); String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "format"; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f5e43c5100a..fc0c688610b 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -156,18 +156,26 @@ typedef struct my_locale_st TYPELIB *ab_day_names; uint max_month_name_length; uint max_day_name_length; + uint decimal_point; + uint thousand_sep; + const char *grouping; #ifdef __cplusplus my_locale_st(uint number_par, const char *name_par, const char *descr_par, bool is_ascii_par, TYPELIB *month_names_par, TYPELIB *ab_month_names_par, TYPELIB *day_names_par, TYPELIB *ab_day_names_par, - uint max_month_name_length_par, uint max_day_name_length_par) : + uint max_month_name_length_par, uint max_day_name_length_par, + uint decimal_point_par, uint thousand_sep_par, + const char *grouping_par) : number(number_par), name(name_par), description(descr_par), is_ascii(is_ascii_par), month_names(month_names_par), ab_month_names(ab_month_names_par), day_names(day_names_par), ab_day_names(ab_day_names_par), max_month_name_length(max_month_name_length_par), - max_day_name_length(max_day_name_length_par) + max_day_name_length(max_day_name_length_par), + decimal_point(decimal_point_par), + thousand_sep(thousand_sep_par), + grouping(grouping_par) {} #endif } MY_LOCALE; diff --git a/sql/set_var.cc b/sql/set_var.cc index 2e2bb369af1..def0be4aff4 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2916,7 +2916,7 @@ bool sys_var_thd_lc_time_names::check(THD *thd, set_var *var) { char buf[20]; int10_to_str((int) var->value->val_int(), buf, -10); - my_printf_error(ER_UNKNOWN_ERROR, "Unknown locale: '%s'", MYF(0), buf); + my_printf_error(ER_UNKNOWN_LOCALE, ER(ER_UNKNOWN_LOCALE), MYF(0), buf); return 1; } } @@ -2932,8 +2932,7 @@ bool sys_var_thd_lc_time_names::check(THD *thd, set_var *var) const char *locale_str= res->c_ptr(); if (!(locale_match= my_locale_by_name(locale_str))) { - my_printf_error(ER_UNKNOWN_ERROR, - "Unknown locale: '%s'", MYF(0), locale_str); + my_printf_error(ER_UNKNOWN_LOCALE, ER(ER_UNKNOWN_LOCALE), MYF(0), locale_str); return 1; } } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 49707f09ca5..a98b3af5dd5 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6228,3 +6228,5 @@ WARN_COND_ITEM_TRUNCATED ER_COND_ITEM_TOO_LONG eng "Data too long for condition item '%s'" +ER_UNKNOWN_LOCALE + eng "Unknown locale: '%-.64s'" diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 3def9864c29..b59c3f16735 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -51,7 +51,10 @@ MY_LOCALE my_locale_ar_AE &my_locale_typelib_day_names_ar_AE, &my_locale_typelib_ab_day_names_ar_AE, 6, - 8 + 8, + '.', /* decimal point ar_AE */ + ',', /* thousands_sep ar_AE */ + "\x03" /* grouping ar_AE */ ); /***** LOCALE END ar_AE *****/ @@ -83,7 +86,10 @@ MY_LOCALE my_locale_ar_BH &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_BH */ + ',', /* thousands_sep ar_BH */ + "\x03" /* grouping ar_BH */ ); /***** LOCALE END ar_BH *****/ @@ -115,7 +121,10 @@ MY_LOCALE my_locale_ar_JO &my_locale_typelib_day_names_ar_JO, &my_locale_typelib_ab_day_names_ar_JO, 12, - 8 + 8, + '.', /* decimal point ar_JO */ + ',', /* thousands_sep ar_JO */ + "\x03" /* grouping ar_JO */ ); /***** LOCALE END ar_JO *****/ @@ -147,7 +156,10 @@ MY_LOCALE my_locale_ar_SA &my_locale_typelib_day_names_ar_SA, &my_locale_typelib_ab_day_names_ar_SA, 12, - 8 + 8, + '.', /* decimal point ar_SA */ + '\0', /* thousands_sep ar_SA */ + "\x80" /* grouping ar_SA */ ); /***** LOCALE END ar_SA *****/ @@ -179,7 +191,10 @@ MY_LOCALE my_locale_ar_SY &my_locale_typelib_day_names_ar_SY, &my_locale_typelib_ab_day_names_ar_SY, 12, - 8 + 8, + '.', /* decimal point ar_SY */ + ',', /* thousands_sep ar_SY */ + "\x03" /* grouping ar_SY */ ); /***** LOCALE END ar_SY *****/ @@ -211,7 +226,10 @@ MY_LOCALE my_locale_be_BY &my_locale_typelib_day_names_be_BY, &my_locale_typelib_ab_day_names_be_BY, 10, - 10 + 10, + ',', /* decimal point be_BY */ + '.', /* thousands_sep be_BY */ + "\x03\x03" /* grouping be_BY */ ); /***** LOCALE END be_BY *****/ @@ -243,7 +261,10 @@ MY_LOCALE my_locale_bg_BG &my_locale_typelib_day_names_bg_BG, &my_locale_typelib_ab_day_names_bg_BG, 9, - 10 + 10, + ',', /* decimal point bg_BG */ + '\0', /* thousands_sep bg_BG */ + "\x03\x03" /* grouping bg_BG */ ); /***** LOCALE END bg_BG *****/ @@ -275,7 +296,11 @@ MY_LOCALE my_locale_ca_ES &my_locale_typelib_day_names_ca_ES, &my_locale_typelib_ab_day_names_ca_ES, 8, - 9 + 9, + ',', /* decimal point ca_ES */ + '\0', /* thousands_sep ca_ES */ + "\x80\x80" /* grouping ca_ES */ + ); /***** LOCALE END ca_ES *****/ @@ -307,7 +332,10 @@ MY_LOCALE my_locale_cs_CZ &my_locale_typelib_day_names_cs_CZ, &my_locale_typelib_ab_day_names_cs_CZ, 8, - 7 + 7, + ',', /* decimal point cs_CZ */ + ' ', /* thousands_sep cs_CZ */ + "\x03\x03" /* grouping cs_CZ */ ); /***** LOCALE END cs_CZ *****/ @@ -339,7 +367,10 @@ MY_LOCALE my_locale_da_DK &my_locale_typelib_day_names_da_DK, &my_locale_typelib_ab_day_names_da_DK, 9, - 7 + 7, + ',', /* decimal point da_DK */ + '.', /* thousands_sep da_DK */ + "\x03\x03" /* grouping da_DK */ ); /***** LOCALE END da_DK *****/ @@ -371,7 +402,10 @@ MY_LOCALE my_locale_de_AT &my_locale_typelib_day_names_de_AT, &my_locale_typelib_ab_day_names_de_AT, 9, - 10 + 10, + ',', /* decimal point de_AT */ + '\0', /* thousands_sep de_AT */ + "\x80\x80" /* grouping de_AT */ ); /***** LOCALE END de_AT *****/ @@ -403,7 +437,10 @@ MY_LOCALE my_locale_de_DE &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE, 9, - 10 + 10, + ',', /* decimal point de_DE */ + '.', /* thousands_sep de_DE */ + "\x03\x03" /* grouping de_DE */ ); /***** LOCALE END de_DE *****/ @@ -435,7 +472,10 @@ MY_LOCALE my_locale_en_US &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_US */ + ',', /* thousands_sep en_US */ + "\x03\x03" /* grouping en_US */ ); /***** LOCALE END en_US *****/ @@ -467,7 +507,10 @@ MY_LOCALE my_locale_es_ES &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_ES */ + '\0', /* thousands_sep es_ES */ + "\x80\x80" /* grouping es_ES */ ); /***** LOCALE END es_ES *****/ @@ -499,7 +542,10 @@ MY_LOCALE my_locale_et_EE &my_locale_typelib_day_names_et_EE, &my_locale_typelib_ab_day_names_et_EE, 9, - 9 + 9, + ',', /* decimal point et_EE */ + ' ', /* thousands_sep et_EE */ + "\x03\x03" /* grouping et_EE */ ); /***** LOCALE END et_EE *****/ @@ -531,7 +577,10 @@ MY_LOCALE my_locale_eu_ES &my_locale_typelib_day_names_eu_ES, &my_locale_typelib_ab_day_names_eu_ES, 9, - 10 + 10, + ',', /* decimal point eu_ES */ + '\0', /* thousands_sep eu_ES */ + "\x80\x80" /* grouping eu_ES */ ); /***** LOCALE END eu_ES *****/ @@ -563,7 +612,10 @@ MY_LOCALE my_locale_fi_FI &my_locale_typelib_day_names_fi_FI, &my_locale_typelib_ab_day_names_fi_FI, 9, - 11 + 11, + ',', /* decimal point fi_FI */ + ' ', /* thousands_sep fi_FI */ + "\x03\x03" /* grouping fi_FI */ ); /***** LOCALE END fi_FI *****/ @@ -595,7 +647,10 @@ MY_LOCALE my_locale_fo_FO &my_locale_typelib_day_names_fo_FO, &my_locale_typelib_ab_day_names_fo_FO, 9, - 12 + 12, + ',', /* decimal point fo_FO */ + '.', /* thousands_sep fo_FO */ + "\x03\x03" /* grouping fo_FO */ ); /***** LOCALE END fo_FO *****/ @@ -627,7 +682,10 @@ MY_LOCALE my_locale_fr_FR &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_FR */ + '\0', /* thousands_sep fr_FR */ + "\x80\x80" /* grouping fr_FR */ ); /***** LOCALE END fr_FR *****/ @@ -659,7 +717,10 @@ MY_LOCALE my_locale_gl_ES &my_locale_typelib_day_names_gl_ES, &my_locale_typelib_ab_day_names_gl_ES, 8, - 8 + 8, + ',', /* decimal point gl_ES */ + '\0', /* thousands_sep gl_ES */ + "\x80\x80" /* grouping gl_ES */ ); /***** LOCALE END gl_ES *****/ @@ -691,7 +752,10 @@ MY_LOCALE my_locale_gu_IN &my_locale_typelib_day_names_gu_IN, &my_locale_typelib_ab_day_names_gu_IN, 10, - 8 + 8, + '.', /* decimal point gu_IN */ + ',', /* thousands_sep gu_IN */ + "\x03" /* grouping gu_IN */ ); /***** LOCALE END gu_IN *****/ @@ -723,7 +787,10 @@ MY_LOCALE my_locale_he_IL &my_locale_typelib_day_names_he_IL, &my_locale_typelib_ab_day_names_he_IL, 7, - 5 + 5, + '.', /* decimal point he_IL */ + ',', /* thousands_sep he_IL */ + "\x03\x03" /* grouping he_IL */ ); /***** LOCALE END he_IL *****/ @@ -755,7 +822,10 @@ MY_LOCALE my_locale_hi_IN &my_locale_typelib_day_names_hi_IN, &my_locale_typelib_ab_day_names_hi_IN, 7, - 9 + 9, + '.', /* decimal point hi_IN */ + ',', /* thousands_sep hi_IN */ + "\x03" /* grouping hi_IN */ ); /***** LOCALE END hi_IN *****/ @@ -787,7 +857,10 @@ MY_LOCALE my_locale_hr_HR &my_locale_typelib_day_names_hr_HR, &my_locale_typelib_ab_day_names_hr_HR, 8, - 11 + 11, + ',', /* decimal point hr_HR */ + '\0', /* thousands_sep hr_HR */ + "\x80\x80" /* grouping hr_HR */ ); /***** LOCALE END hr_HR *****/ @@ -819,7 +892,10 @@ MY_LOCALE my_locale_hu_HU &my_locale_typelib_day_names_hu_HU, &my_locale_typelib_ab_day_names_hu_HU, 10, - 9 + 9, + ',', /* decimal point hu_HU */ + '.', /* thousands_sep hu_HU */ + "\x03\x03" /* grouping hu_HU */ ); /***** LOCALE END hu_HU *****/ @@ -851,7 +927,10 @@ MY_LOCALE my_locale_id_ID &my_locale_typelib_day_names_id_ID, &my_locale_typelib_ab_day_names_id_ID, 9, - 6 + 6, + ',', /* decimal point id_ID */ + '.', /* thousands_sep id_ID */ + "\x03\x03" /* grouping id_ID */ ); /***** LOCALE END id_ID *****/ @@ -883,7 +962,10 @@ MY_LOCALE my_locale_is_IS &my_locale_typelib_day_names_is_IS, &my_locale_typelib_ab_day_names_is_IS, 9, - 12 + 12, + ',', /* decimal point is_IS */ + '.', /* thousands_sep is_IS */ + "\x03\x03" /* grouping is_IS */ ); /***** LOCALE END is_IS *****/ @@ -915,7 +997,10 @@ MY_LOCALE my_locale_it_CH &my_locale_typelib_day_names_it_CH, &my_locale_typelib_ab_day_names_it_CH, 9, - 9 + 9, + ',', /* decimal point it_CH */ + '\'', /* thousands_sep it_CH */ + "\x03\x03" /* grouping it_CH */ ); /***** LOCALE END it_CH *****/ @@ -947,7 +1032,10 @@ MY_LOCALE my_locale_ja_JP &my_locale_typelib_day_names_ja_JP, &my_locale_typelib_ab_day_names_ja_JP, 3, - 3 + 3, + '.', /* decimal point ja_JP */ + ',', /* thousands_sep ja_JP */ + "\x03" /* grouping ja_JP */ ); /***** LOCALE END ja_JP *****/ @@ -979,7 +1067,10 @@ MY_LOCALE my_locale_ko_KR &my_locale_typelib_day_names_ko_KR, &my_locale_typelib_ab_day_names_ko_KR, 3, - 3 + 3, + '.', /* decimal point ko_KR */ + ',', /* thousands_sep ko_KR */ + "\x03\x03" /* grouping ko_KR */ ); /***** LOCALE END ko_KR *****/ @@ -1011,7 +1102,10 @@ MY_LOCALE my_locale_lt_LT &my_locale_typelib_day_names_lt_LT, &my_locale_typelib_ab_day_names_lt_LT, 9, - 14 + 14, + ',', /* decimal point lt_LT */ + '.', /* thousands_sep lt_LT */ + "\x03\x03" /* grouping lt_LT */ ); /***** LOCALE END lt_LT *****/ @@ -1043,7 +1137,10 @@ MY_LOCALE my_locale_lv_LV &my_locale_typelib_day_names_lv_LV, &my_locale_typelib_ab_day_names_lv_LV, 10, - 11 + 11, + ',', /* decimal point lv_LV */ + ' ', /* thousands_sep lv_LV */ + "\x03\x03" /* grouping lv_LV */ ); /***** LOCALE END lv_LV *****/ @@ -1075,7 +1172,10 @@ MY_LOCALE my_locale_mk_MK &my_locale_typelib_day_names_mk_MK, &my_locale_typelib_ab_day_names_mk_MK, 9, - 10 + 10, + ',', /* decimal point mk_MK */ + ' ', /* thousands_sep mk_MK */ + "\x03\x03" /* grouping mk_MK */ ); /***** LOCALE END mk_MK *****/ @@ -1107,7 +1207,10 @@ MY_LOCALE my_locale_mn_MN &my_locale_typelib_day_names_mn_MN, &my_locale_typelib_ab_day_names_mn_MN, 18, - 6 + 6, + ',', /* decimal point mn_MN */ + '.', /* thousands_sep mn_MN */ + "\x03\x03" /* grouping mn_MN */ ); /***** LOCALE END mn_MN *****/ @@ -1139,7 +1242,10 @@ MY_LOCALE my_locale_ms_MY &my_locale_typelib_day_names_ms_MY, &my_locale_typelib_ab_day_names_ms_MY, 9, - 6 + 6, + '.', /* decimal point ms_MY */ + ',', /* thousands_sep ms_MY */ + "\x03" /* grouping ms_MY */ ); /***** LOCALE END ms_MY *****/ @@ -1171,7 +1277,10 @@ MY_LOCALE my_locale_nb_NO &my_locale_typelib_day_names_nb_NO, &my_locale_typelib_ab_day_names_nb_NO, 9, - 7 + 7, + ',', /* decimal point nb_NO */ + '.', /* thousands_sep nb_NO */ + "\x03\x03" /* grouping nb_NO */ ); /***** LOCALE END nb_NO *****/ @@ -1203,7 +1312,10 @@ MY_LOCALE my_locale_nl_NL &my_locale_typelib_day_names_nl_NL, &my_locale_typelib_ab_day_names_nl_NL, 9, - 9 + 9, + ',', /* decimal point nl_NL */ + '\0', /* thousands_sep nl_NL */ + "\x80\x80" /* grouping nl_NL */ ); /***** LOCALE END nl_NL *****/ @@ -1235,7 +1347,10 @@ MY_LOCALE my_locale_pl_PL &my_locale_typelib_day_names_pl_PL, &my_locale_typelib_ab_day_names_pl_PL, 11, - 12 + 12, + ',', /* decimal point pl_PL */ + '\0', /* thousands_sep pl_PL */ + "\x80\x80" /* grouping pl_PL */ ); /***** LOCALE END pl_PL *****/ @@ -1267,7 +1382,10 @@ MY_LOCALE my_locale_pt_BR &my_locale_typelib_day_names_pt_BR, &my_locale_typelib_ab_day_names_pt_BR, 9, - 7 + 7, + ',', /* decimal point pt_BR */ + '\0', /* thousands_sep pt_BR */ + "\x80\x80" /* grouping pt_BR */ ); /***** LOCALE END pt_BR *****/ @@ -1299,7 +1417,10 @@ MY_LOCALE my_locale_pt_PT &my_locale_typelib_day_names_pt_PT, &my_locale_typelib_ab_day_names_pt_PT, 9, - 7 + 7, + ',', /* decimal point pt_PT */ + '\0', /* thousands_sep pt_PT */ + "\x80\x80" /* grouping pt_PT */ ); /***** LOCALE END pt_PT *****/ @@ -1331,7 +1452,10 @@ MY_LOCALE my_locale_ro_RO &my_locale_typelib_day_names_ro_RO, &my_locale_typelib_ab_day_names_ro_RO, 10, - 8 + 8, + ',', /* decimal point ro_RO */ + '.', /* thousands_sep ro_RO */ + "\x03\x03" /* grouping ro_RO */ ); /***** LOCALE END ro_RO *****/ @@ -1363,7 +1487,10 @@ MY_LOCALE my_locale_ru_RU &my_locale_typelib_day_names_ru_RU, &my_locale_typelib_ab_day_names_ru_RU, 8, - 11 + 11, + ',', /* decimal point ru_RU */ + ' ', /* thousands_sep ru_RU */ + "\x03\x03" /* grouping ru_RU */ ); /***** LOCALE END ru_RU *****/ @@ -1395,7 +1522,10 @@ MY_LOCALE my_locale_ru_UA &my_locale_typelib_day_names_ru_UA, &my_locale_typelib_ab_day_names_ru_UA, 8, - 11 + 11, + ',', /* decimal point ru_UA */ + '.', /* thousands_sep ru_UA */ + "\x03\x03" /* grouping ru_UA */ ); /***** LOCALE END ru_UA *****/ @@ -1427,7 +1557,10 @@ MY_LOCALE my_locale_sk_SK &my_locale_typelib_day_names_sk_SK, &my_locale_typelib_ab_day_names_sk_SK, 9, - 8 + 8, + ',', /* decimal point sk_SK */ + ' ', /* thousands_sep sk_SK */ + "\x03\x03" /* grouping sk_SK */ ); /***** LOCALE END sk_SK *****/ @@ -1459,7 +1592,10 @@ MY_LOCALE my_locale_sl_SI &my_locale_typelib_day_names_sl_SI, &my_locale_typelib_ab_day_names_sl_SI, 9, - 10 + 10, + ',', /* decimal point sl_SI */ + ' ', /* thousands_sep sl_SI */ + "\x80\x80" /* grouping sl_SI */ ); /***** LOCALE END sl_SI *****/ @@ -1491,7 +1627,10 @@ MY_LOCALE my_locale_sq_AL &my_locale_typelib_day_names_sq_AL, &my_locale_typelib_ab_day_names_sq_AL, 7, - 10 + 10, + ',', /* decimal point sq_AL */ + '.', /* thousands_sep sq_AL */ + "\x03" /* grouping sq_AL */ ); /***** LOCALE END sq_AL *****/ @@ -1523,7 +1662,10 @@ MY_LOCALE my_locale_sr_YU &my_locale_typelib_day_names_sr_YU, &my_locale_typelib_ab_day_names_sr_YU, 9, - 10 + 10, + '.', /* decimal point sr_YU */ + '\0', /* thousands_sep sr_YU */ + "\x80" /* grouping sr_YU */ ); /***** LOCALE END sr_YU *****/ @@ -1555,7 +1697,10 @@ MY_LOCALE my_locale_sv_SE &my_locale_typelib_day_names_sv_SE, &my_locale_typelib_ab_day_names_sv_SE, 9, - 7 + 7, + ',', /* decimal point sv_SE */ + ' ', /* thousands_sep sv_SE */ + "\x03\x03" /* grouping sv_SE */ ); /***** LOCALE END sv_SE *****/ @@ -1587,7 +1732,10 @@ MY_LOCALE my_locale_ta_IN &my_locale_typelib_day_names_ta_IN, &my_locale_typelib_ab_day_names_ta_IN, 10, - 8 + 8, + '.', /* decimal point ta_IN */ + ',', /* thousands_sep ta_IN */ + "\x03\x02" /* grouping ta_IN */ ); /***** LOCALE END ta_IN *****/ @@ -1619,7 +1767,10 @@ MY_LOCALE my_locale_te_IN &my_locale_typelib_day_names_te_IN, &my_locale_typelib_ab_day_names_te_IN, 10, - 9 + 9, + '.', /* decimal point te_IN */ + ',', /* thousands_sep te_IN */ + "\x03\x02" /* grouping te_IN */ ); /***** LOCALE END te_IN *****/ @@ -1651,7 +1802,10 @@ MY_LOCALE my_locale_th_TH &my_locale_typelib_day_names_th_TH, &my_locale_typelib_ab_day_names_th_TH, 10, - 8 + 8, + '.', /* decimal point th_TH */ + ',', /* thousands_sep th_TH */ + "\x03" /* grouping th_TH */ ); /***** LOCALE END th_TH *****/ @@ -1683,7 +1837,10 @@ MY_LOCALE my_locale_tr_TR &my_locale_typelib_day_names_tr_TR, &my_locale_typelib_ab_day_names_tr_TR, 7, - 9 + 9, + ',', /* decimal point tr_TR */ + '.', /* thousands_sep tr_TR */ + "\x03\x03" /* grouping tr_TR */ ); /***** LOCALE END tr_TR *****/ @@ -1715,7 +1872,10 @@ MY_LOCALE my_locale_uk_UA &my_locale_typelib_day_names_uk_UA, &my_locale_typelib_ab_day_names_uk_UA, 8, - 9 + 9, + ',', /* decimal point uk_UA */ + '.', /* thousands_sep uk_UA */ + "\x03\x03" /* grouping uk_UA */ ); /***** LOCALE END uk_UA *****/ @@ -1747,7 +1907,10 @@ MY_LOCALE my_locale_ur_PK &my_locale_typelib_day_names_ur_PK, &my_locale_typelib_ab_day_names_ur_PK, 6, - 6 + 6, + '.', /* decimal point ur_PK */ + ',', /* thousands_sep ur_PK */ + "\x03\x03" /* grouping ur_PK */ ); /***** LOCALE END ur_PK *****/ @@ -1779,7 +1942,10 @@ MY_LOCALE my_locale_vi_VN &my_locale_typelib_day_names_vi_VN, &my_locale_typelib_ab_day_names_vi_VN, 16, - 11 + 11, + ',', /* decimal point vi_VN */ + '.', /* thousands_sep vi_VN */ + "\x03\x03" /* grouping vi_VN */ ); /***** LOCALE END vi_VN *****/ @@ -1811,7 +1977,10 @@ MY_LOCALE my_locale_zh_CN &my_locale_typelib_day_names_zh_CN, &my_locale_typelib_ab_day_names_zh_CN, 3, - 3 + 3, + '.', /* decimal point zh_CN */ + ',', /* thousands_sep zh_CN */ + "\x03" /* grouping zh_CN */ ); /***** LOCALE END zh_CN *****/ @@ -1843,7 +2012,10 @@ MY_LOCALE my_locale_zh_TW &my_locale_typelib_day_names_zh_TW, &my_locale_typelib_ab_day_names_zh_TW, 3, - 2 + 2, + '.', /* decimal point zh_TW */ + ',', /* thousands_sep zh_TW */ + "\x03" /* grouping zh_TW */ ); /***** LOCALE END zh_TW *****/ @@ -1859,7 +2031,10 @@ MY_LOCALE my_locale_ar_DZ &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_DZ */ + ',', /* thousands_sep ar_DZ */ + "\x03" /* grouping ar_DZ */ ); /***** LOCALE END ar_DZ *****/ @@ -1875,7 +2050,10 @@ MY_LOCALE my_locale_ar_EG &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_EG */ + ',', /* thousands_sep ar_EG */ + "\x03" /* grouping ar_EG */ ); /***** LOCALE END ar_EG *****/ @@ -1891,7 +2069,10 @@ MY_LOCALE my_locale_ar_IN &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_IN */ + ',', /* thousands_sep ar_IN */ + "\x03" /* grouping ar_IN */ ); /***** LOCALE END ar_IN *****/ @@ -1907,7 +2088,10 @@ MY_LOCALE my_locale_ar_IQ &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_IQ */ + ',', /* thousands_sep ar_IQ */ + "\x03" /* grouping ar_IQ */ ); /***** LOCALE END ar_IQ *****/ @@ -1923,7 +2107,10 @@ MY_LOCALE my_locale_ar_KW &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_KW */ + ',', /* thousands_sep ar_KW */ + "\x03" /* grouping ar_KW */ ); /***** LOCALE END ar_KW *****/ @@ -1939,7 +2126,10 @@ MY_LOCALE my_locale_ar_LB &my_locale_typelib_day_names_ar_JO, &my_locale_typelib_ab_day_names_ar_JO, 12, - 8 + 8, + '.', /* decimal point ar_LB */ + ',', /* thousands_sep ar_LB */ + "\x03" /* grouping ar_LB */ ); /***** LOCALE END ar_LB *****/ @@ -1955,7 +2145,10 @@ MY_LOCALE my_locale_ar_LY &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_LY */ + ',', /* thousands_sep ar_LY */ + "\x03" /* grouping ar_LY */ ); /***** LOCALE END ar_LY *****/ @@ -1971,7 +2164,10 @@ MY_LOCALE my_locale_ar_MA &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_MA */ + ',', /* thousands_sep ar_MA */ + "\x03" /* grouping ar_MA */ ); /***** LOCALE END ar_MA *****/ @@ -1987,7 +2183,10 @@ MY_LOCALE my_locale_ar_OM &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_OM */ + ',', /* thousands_sep ar_OM */ + "\x03" /* grouping ar_OM */ ); /***** LOCALE END ar_OM *****/ @@ -2003,7 +2202,10 @@ MY_LOCALE my_locale_ar_QA &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_QA */ + ',', /* thousands_sep ar_QA */ + "\x03" /* grouping ar_QA */ ); /***** LOCALE END ar_QA *****/ @@ -2019,7 +2221,10 @@ MY_LOCALE my_locale_ar_SD &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_SD */ + ',', /* thousands_sep ar_SD */ + "\x03" /* grouping ar_SD */ ); /***** LOCALE END ar_SD *****/ @@ -2035,7 +2240,10 @@ MY_LOCALE my_locale_ar_TN &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_TN */ + ',', /* thousands_sep ar_TN */ + "\x03" /* grouping ar_TN */ ); /***** LOCALE END ar_TN *****/ @@ -2051,7 +2259,10 @@ MY_LOCALE my_locale_ar_YE &my_locale_typelib_day_names_ar_BH, &my_locale_typelib_ab_day_names_ar_BH, 6, - 8 + 8, + '.', /* decimal point ar_YE */ + ',', /* thousands_sep ar_YE */ + "\x03" /* grouping ar_YE */ ); /***** LOCALE END ar_YE *****/ @@ -2067,7 +2278,10 @@ MY_LOCALE my_locale_de_BE &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE, 9, - 10 + 10, + ',', /* decimal point de_BE */ + '.', /* thousands_sep de_BE */ + "\x03\x03" /* grouping de_BE */ ); /***** LOCALE END de_BE *****/ @@ -2083,7 +2297,10 @@ MY_LOCALE my_locale_de_CH &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE, 9, - 10 + 10, + '.', /* decimal point de_CH */ + '\'', /* thousands_sep de_CH */ + "\x03\x03" /* grouping de_CH */ ); /***** LOCALE END de_CH *****/ @@ -2099,7 +2316,10 @@ MY_LOCALE my_locale_de_LU &my_locale_typelib_day_names_de_DE, &my_locale_typelib_ab_day_names_de_DE, 9, - 10 + 10, + ',', /* decimal point de_LU */ + '.', /* thousands_sep de_LU */ + "\x03\x03" /* grouping de_LU */ ); /***** LOCALE END de_LU *****/ @@ -2115,7 +2335,10 @@ MY_LOCALE my_locale_en_AU &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_AU */ + ',', /* thousands_sep en_AU */ + "\x03\x03" /* grouping en_AU */ ); /***** LOCALE END en_AU *****/ @@ -2131,7 +2354,10 @@ MY_LOCALE my_locale_en_CA &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_CA */ + ',', /* thousands_sep en_CA */ + "\x03\x03" /* grouping en_CA */ ); /***** LOCALE END en_CA *****/ @@ -2147,7 +2373,10 @@ MY_LOCALE my_locale_en_GB &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_GB */ + ',', /* thousands_sep en_GB */ + "\x03\x03" /* grouping en_GB */ ); /***** LOCALE END en_GB *****/ @@ -2163,7 +2392,10 @@ MY_LOCALE my_locale_en_IN &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_IN */ + ',', /* thousands_sep en_IN */ + "\x03\x02" /* grouping en_IN */ ); /***** LOCALE END en_IN *****/ @@ -2179,7 +2411,10 @@ MY_LOCALE my_locale_en_NZ &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_NZ */ + ',', /* thousands_sep en_NZ */ + "\x03\x03" /* grouping en_NZ */ ); /***** LOCALE END en_NZ *****/ @@ -2195,7 +2430,10 @@ MY_LOCALE my_locale_en_PH &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_PH */ + ',', /* thousands_sep en_PH */ + "\x03" /* grouping en_PH */ ); /***** LOCALE END en_PH *****/ @@ -2211,7 +2449,10 @@ MY_LOCALE my_locale_en_ZA &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_ZA */ + ',', /* thousands_sep en_ZA */ + "\x03\x03" /* grouping en_ZA */ ); /***** LOCALE END en_ZA *****/ @@ -2227,7 +2468,10 @@ MY_LOCALE my_locale_en_ZW &my_locale_typelib_day_names_en_US, &my_locale_typelib_ab_day_names_en_US, 9, - 9 + 9, + '.', /* decimal point en_ZW */ + ',', /* thousands_sep en_ZW */ + "\x03\x03" /* grouping en_ZW */ ); /***** LOCALE END en_ZW *****/ @@ -2243,7 +2487,10 @@ MY_LOCALE my_locale_es_AR &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_AR */ + '.', /* thousands_sep es_AR */ + "\x03\x03" /* grouping es_AR */ ); /***** LOCALE END es_AR *****/ @@ -2259,7 +2506,10 @@ MY_LOCALE my_locale_es_BO &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_BO */ + '\0', /* thousands_sep es_BO */ + "\x80\x80" /* grouping es_BO */ ); /***** LOCALE END es_BO *****/ @@ -2275,7 +2525,10 @@ MY_LOCALE my_locale_es_CL &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_CL */ + '\0', /* thousands_sep es_CL */ + "\x80\x80" /* grouping es_CL */ ); /***** LOCALE END es_CL *****/ @@ -2291,7 +2544,10 @@ MY_LOCALE my_locale_es_CO &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_CO */ + '\0', /* thousands_sep es_CO */ + "\x80\x80" /* grouping es_CO */ ); /***** LOCALE END es_CO *****/ @@ -2307,7 +2563,10 @@ MY_LOCALE my_locale_es_CR &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_CR */ + '\0', /* thousands_sep es_CR */ + "\x80\x80" /* grouping es_CR */ ); /***** LOCALE END es_CR *****/ @@ -2323,7 +2582,10 @@ MY_LOCALE my_locale_es_DO &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_DO */ + '\0', /* thousands_sep es_DO */ + "\x80\x80" /* grouping es_DO */ ); /***** LOCALE END es_DO *****/ @@ -2339,7 +2601,10 @@ MY_LOCALE my_locale_es_EC &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_EC */ + '\0', /* thousands_sep es_EC */ + "\x80\x80" /* grouping es_EC */ ); /***** LOCALE END es_EC *****/ @@ -2355,7 +2620,10 @@ MY_LOCALE my_locale_es_GT &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_GT */ + '\0', /* thousands_sep es_GT */ + "\x80\x80" /* grouping es_GT */ ); /***** LOCALE END es_GT *****/ @@ -2371,7 +2639,10 @@ MY_LOCALE my_locale_es_HN &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_HN */ + '\0', /* thousands_sep es_HN */ + "\x80\x80" /* grouping es_HN */ ); /***** LOCALE END es_HN *****/ @@ -2387,7 +2658,10 @@ MY_LOCALE my_locale_es_MX &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_MX */ + '\0', /* thousands_sep es_MX */ + "\x80\x80" /* grouping es_MX */ ); /***** LOCALE END es_MX *****/ @@ -2403,7 +2677,10 @@ MY_LOCALE my_locale_es_NI &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_NI */ + '\0', /* thousands_sep es_NI */ + "\x80\x80" /* grouping es_NI */ ); /***** LOCALE END es_NI *****/ @@ -2419,7 +2696,10 @@ MY_LOCALE my_locale_es_PA &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_PA */ + '\0', /* thousands_sep es_PA */ + "\x80\x80" /* grouping es_PA */ ); /***** LOCALE END es_PA *****/ @@ -2435,7 +2715,10 @@ MY_LOCALE my_locale_es_PE &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_PE */ + '\0', /* thousands_sep es_PE */ + "\x80\x80" /* grouping es_PE */ ); /***** LOCALE END es_PE *****/ @@ -2451,7 +2734,10 @@ MY_LOCALE my_locale_es_PR &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_PR */ + '\0', /* thousands_sep es_PR */ + "\x80\x80" /* grouping es_PR */ ); /***** LOCALE END es_PR *****/ @@ -2467,7 +2753,10 @@ MY_LOCALE my_locale_es_PY &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_PY */ + '\0', /* thousands_sep es_PY */ + "\x80\x80" /* grouping es_PY */ ); /***** LOCALE END es_PY *****/ @@ -2483,7 +2772,10 @@ MY_LOCALE my_locale_es_SV &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_SV */ + '\0', /* thousands_sep es_SV */ + "\x80\x80" /* grouping es_SV */ ); /***** LOCALE END es_SV *****/ @@ -2499,7 +2791,10 @@ MY_LOCALE my_locale_es_US &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + '.', /* decimal point es_US */ + ',', /* thousands_sep es_US */ + "\x03\x03" /* grouping es_US */ ); /***** LOCALE END es_US *****/ @@ -2515,7 +2810,10 @@ MY_LOCALE my_locale_es_UY &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_UY */ + '\0', /* thousands_sep es_UY */ + "\x80\x80" /* grouping es_UY */ ); /***** LOCALE END es_UY *****/ @@ -2531,7 +2829,10 @@ MY_LOCALE my_locale_es_VE &my_locale_typelib_day_names_es_ES, &my_locale_typelib_ab_day_names_es_ES, 10, - 9 + 9, + ',', /* decimal point es_VE */ + '\0', /* thousands_sep es_VE */ + "\x80\x80" /* grouping es_VE */ ); /***** LOCALE END es_VE *****/ @@ -2547,7 +2848,10 @@ MY_LOCALE my_locale_fr_BE &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_BE */ + '.', /* thousands_sep fr_BE */ + "\x80\x80" /* grouping fr_BE */ ); /***** LOCALE END fr_BE *****/ @@ -2563,7 +2867,10 @@ MY_LOCALE my_locale_fr_CA &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_CA */ + ' ', /* thousands_sep fr_CA */ + "\x80\x80" /* grouping fr_CA */ ); /***** LOCALE END fr_CA *****/ @@ -2579,7 +2886,10 @@ MY_LOCALE my_locale_fr_CH &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_CH */ + '\0', /* thousands_sep fr_CH */ + "\x80\x80" /* grouping fr_CH */ ); /***** LOCALE END fr_CH *****/ @@ -2595,7 +2905,10 @@ MY_LOCALE my_locale_fr_LU &my_locale_typelib_day_names_fr_FR, &my_locale_typelib_ab_day_names_fr_FR, 9, - 8 + 8, + ',', /* decimal point fr_LU */ + '\0', /* thousands_sep fr_LU */ + "\x80\x80" /* grouping fr_LU */ ); /***** LOCALE END fr_LU *****/ @@ -2611,7 +2924,10 @@ MY_LOCALE my_locale_it_IT &my_locale_typelib_day_names_it_CH, &my_locale_typelib_ab_day_names_it_CH, 9, - 9 + 9, + ',', /* decimal point it_IT */ + '\0', /* thousands_sep it_IT */ + "\x80\x80" /* grouping it_IT */ ); /***** LOCALE END it_IT *****/ @@ -2627,7 +2943,10 @@ MY_LOCALE my_locale_nl_BE &my_locale_typelib_day_names_nl_NL, &my_locale_typelib_ab_day_names_nl_NL, 9, - 9 + 9, + ',', /* decimal point nl_BE */ + '.', /* thousands_sep nl_BE */ + "\x80\x80" /* grouping nl_BE */ ); /***** LOCALE END nl_BE *****/ @@ -2643,7 +2962,10 @@ MY_LOCALE my_locale_no_NO &my_locale_typelib_day_names_nb_NO, &my_locale_typelib_ab_day_names_nb_NO, 9, - 7 + 7, + ',', /* decimal point no_NO */ + '.', /* thousands_sep no_NO */ + "\x03\x03" /* grouping no_NO */ ); /***** LOCALE END no_NO *****/ @@ -2659,7 +2981,10 @@ MY_LOCALE my_locale_sv_FI &my_locale_typelib_day_names_sv_SE, &my_locale_typelib_ab_day_names_sv_SE, 9, - 7 + 7, + ',', /* decimal point sv_FI */ + ' ', /* thousands_sep sv_FI */ + "\x03\x03" /* grouping sv_FI */ ); /***** LOCALE END sv_FI *****/ @@ -2675,7 +3000,11 @@ MY_LOCALE my_locale_zh_HK &my_locale_typelib_day_names_zh_CN, &my_locale_typelib_ab_day_names_zh_CN, 3, - 3 + 3, + '.', /* decimal point zh_HK */ + ',', /* thousands_sep zh_HK */ + "\x03" /* grouping zh_HK */ + ); /***** LOCALE END zh_HK *****/ From 56312dc7cf7cc3be5e510b3ef743cb29d8783b7e Mon Sep 17 00:00:00 2001 From: Guilhem Bichot Date: Mon, 5 Oct 2009 22:59:19 +0200 Subject: [PATCH 081/274] Backport of the fix for BUG#33730 "Full table scan instead selected partitions for query more than 10 partitions" from 6.0, made in sergefp@mysql.com-20090205190644-q8632sniogedhtsu --- mysql-test/r/partition_hash.result | 2 +- mysql-test/r/partition_pruning.result | 19 ++++++++++++++++ mysql-test/t/partition_pruning.test | 19 ++++++++++++++++ sql/sql_partition.cc | 32 ++++++++++++++++----------- 4 files changed, 58 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/partition_hash.result b/mysql-test/r/partition_hash.result index 19da70db5a0..dcefd70ff43 100644 --- a/mysql-test/r/partition_hash.result +++ b/mysql-test/r/partition_hash.result @@ -93,7 +93,7 @@ id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p0,p1,p2,p3 ALL NULL NULL NULL NULL 9 Using where explain partitions select * from t1 where a >= 1 and a <= 5; id select_type table partitions type possible_keys key key_len ref rows Extra -1 SIMPLE t1 p0,p1,p2,p3 ALL NULL NULL NULL NULL 9 Using where +1 SIMPLE t1 p0,p1,p2 ALL NULL NULL NULL NULL 9 Using where drop table t1; CREATE TABLE t1 ( a int not null, diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 769d499fc0a..d8bff2cbe01 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -2229,3 +2229,22 @@ explain partitions select * from t1 where recdate < '2006-01-01 00:00:00'; id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 2 Using where drop table t1; +# +# BUG#33730 Full table scan instead selected partitions for query more than 10 partitions +# +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (a int) +partition by range(a+0) ( +partition p0 values less than (64), +partition p1 values less than (128), +partition p2 values less than (255) +); +insert into t1 select A.a + 10*B.a from t0 A, t0 B; +explain partitions select * from t1 where a between 10 and 13; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 64 Using where +explain partitions select * from t1 where a between 10 and 10+33; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1,p2 ALL NULL NULL NULL NULL 100 Using where +drop table t0, t1; diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test index 11e65be45fc..ea72cef5b62 100644 --- a/mysql-test/t/partition_pruning.test +++ b/mysql-test/t/partition_pruning.test @@ -1159,3 +1159,22 @@ INSERT INTO t1 VALUES ('2006-03-01 12:00:00'); -- echo must use p0 only: explain partitions select * from t1 where recdate < '2006-01-01 00:00:00'; drop table t1; + +-- echo # +-- echo # BUG#33730 Full table scan instead selected partitions for query more than 10 partitions +-- echo # +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t1 (a int) + partition by range(a+0) ( + partition p0 values less than (64), + partition p1 values less than (128), + partition p2 values less than (255) +); +insert into t1 select A.a + 10*B.a from t0 A, t0 B; + +# this will use interval_via_walking +explain partitions select * from t1 where a between 10 and 13; +explain partitions select * from t1 where a between 10 and 10+33; + +drop table t0, t1; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index f6a8e895fdc..a67ed1cf3af 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6850,7 +6850,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, /* See get_part_iter_for_interval_via_walking for definition of what this is */ -#define MAX_RANGE_TO_WALK 10 +#define MAX_RANGE_TO_WALK 32 /* @@ -6886,16 +6886,6 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, Intervals with +inf/-inf, and [NULL, c1] interval can be processed but that is more tricky and I don't have time to do it right now. - Additionally we have these requirements: - * number of values in the interval must be less then number of - [sub]partitions, and - * Number of values in the interval must be less then MAX_RANGE_TO_WALK. - - The rationale behind these requirements is that if they are not met - we're likely to hit most of the partitions and traversing the interval - will only add overhead. So it's better return "all partitions used" in - that case. - RETURN 0 - No matching partitions, iterator not initialized 1 - Some partitions would match, iterator intialized for traversing them @@ -6989,8 +6979,24 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, a += test(flags & NEAR_MIN); b += test(!(flags & NEAR_MAX)); ulonglong n_values= b - a; - - if (n_values > total_parts || n_values > MAX_RANGE_TO_WALK) + + /* + Will it pay off to enumerate all values in the [a..b] range and evaluate + the partitioning function for every value? It depends on + 1. whether we'll be able to infer that some partitions are not used + 2. if time savings from not scanning these partitions will be greater + than time spent in enumeration. + We will assume that the cost of accessing one extra partition is greater + than the cost of evaluating the partitioning function O(#partitions). + This means we should jump at any chance to eliminate a partition, which + gives us this logic: + + Do the enumeration if + - the number of values to enumerate is comparable to the number of + partitions, or + - there are not many values to enumerate. + */ + if ((n_values > 2*total_parts) && n_values > MAX_RANGE_TO_WALK) return -1; part_iter->field_vals.start= part_iter->field_vals.cur= a; From 27936529e06368557e1b662d020a87690af200f4 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 6 Oct 2009 11:02:51 +0500 Subject: [PATCH 082/274] Backporting WL#4642 Greek locale for DAYNAME, MONTHNAME, DATE_FORMAT added: mysql-test/r/locale.result mysql-test/t/locale.test modified: mysql-test/r/variables.result mysql-test/t/variables.test sql/sql_locale.cc --- mysql-test/r/locale.result | 49 ++++++++++++++++++++++++ mysql-test/r/variables.result | 14 +++---- mysql-test/t/locale.test | 34 +++++++++++++++++ mysql-test/t/variables.test | 4 +- sql/sql_locale.cc | 72 +++++++++++++++++++++++++++++++++++ 5 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 mysql-test/r/locale.result create mode 100644 mysql-test/t/locale.test diff --git a/mysql-test/r/locale.result b/mysql-test/r/locale.result new file mode 100644 index 00000000000..467eb97b639 --- /dev/null +++ b/mysql-test/r/locale.result @@ -0,0 +1,49 @@ +DROP TABLE IF EXISTS t1; +Start of 5.4 tests +# +# WL#4642 Greek locale for DAYNAME, MONTHNAME, DATE_FORMAT +# +SET NAMES utf8; +SET @@lc_time_names=109; +SELECT @@lc_time_names; +@@lc_time_names +el_GR +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES +('2006-01-01'),('2006-01-02'),('2006-01-03'), +('2006-01-04'),('2006-01-05'),('2006-01-06'),('2006-01-07'); +SELECT a, date_format(a,'%a') as abday, dayname(a) as day FROM t1 ORDER BY a; +a abday day +2006-01-01 ÎšÏ…Ï ÎšÏ…Ïιακή +2006-01-02 Δευ ΔευτέÏα +2006-01-03 ΤÏί ΤÏίτη +2006-01-04 Τετ ΤετάÏτη +2006-01-05 Πέμ Πέμπτη +2006-01-06 Î Î±Ï Î Î±Ïασκευή +2006-01-07 Σάβ Σάββατο +DROP TABLE t1; +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES +('2006-01-01'),('2006-02-01'),('2006-03-01'), +('2006-04-01'),('2006-05-01'),('2006-06-01'), +('2006-07-01'),('2006-08-01'),('2006-09-01'), +('2006-10-01'),('2006-11-01'),('2006-12-01'); +SELECT a, date_format(a,'%b') as abmon, monthname(a) as mon FROM t1 ORDER BY a; +a abmon mon +2006-01-01 Ιαν ΙανουάÏιος +2006-02-01 Φεβ ΦεβÏουάÏιος +2006-03-01 ÎœÎ¬Ï ÎœÎ¬Ïτιος +2006-04-01 Î‘Ï€Ï Î‘Ï€Ïίλιος +2006-05-01 Μάι Μάιος +2006-06-01 ΙοÏν ΙοÏνιος +2006-07-01 ΙοÏλ ΙοÏλιος +2006-08-01 ΑÏγ ΑÏγουστος +2006-09-01 Σεπ ΣεπτέμβÏιος +2006-10-01 Οκτ ΟκτώβÏιος +2006-11-01 Îοέ ÎοέμβÏιος +2006-12-01 Δεκ ΔεκέμβÏιος +SELECT format(123456.789, 3, 'el_GR'); +format(123456.789, 3, 'el_GR') +123456.789 +DROP TABLE t1; +End of 5.4 tests diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index c1cd1840df8..da833c79bb7 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -812,16 +812,16 @@ select @@lc_time_names; @@lc_time_names en_US LC_TIME_NAMES: testing locale with the last ID: -set lc_time_names=108; -select @@lc_time_names; -@@lc_time_names -zh_HK -LC_TIME_NAMES: testing a number beyond the valid ID range: set lc_time_names=109; -ERROR HY000: Unknown locale: '109' select @@lc_time_names; @@lc_time_names -zh_HK +el_GR +LC_TIME_NAMES: testing a number beyond the valid ID range: +set lc_time_names=110; +ERROR HY000: Unknown locale: '110' +select @@lc_time_names; +@@lc_time_names +el_GR LC_TIME_NAMES: testing that 0 is en_US: set lc_time_names=0; select @@lc_time_names; diff --git a/mysql-test/t/locale.test b/mysql-test/t/locale.test new file mode 100644 index 00000000000..a6291d9048d --- /dev/null +++ b/mysql-test/t/locale.test @@ -0,0 +1,34 @@ +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--echo Start of 5.4 tests + +--echo # +--echo # WL#4642 Greek locale for DAYNAME, MONTHNAME, DATE_FORMAT +--echo # + +SET NAMES utf8; + +SET @@lc_time_names=109; +SELECT @@lc_time_names; + +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES +('2006-01-01'),('2006-01-02'),('2006-01-03'), +('2006-01-04'),('2006-01-05'),('2006-01-06'),('2006-01-07'); +SELECT a, date_format(a,'%a') as abday, dayname(a) as day FROM t1 ORDER BY a; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES +('2006-01-01'),('2006-02-01'),('2006-03-01'), +('2006-04-01'),('2006-05-01'),('2006-06-01'), +('2006-07-01'),('2006-08-01'),('2006-09-01'), +('2006-10-01'),('2006-11-01'),('2006-12-01'); +SELECT a, date_format(a,'%b') as abmon, monthname(a) as mon FROM t1 ORDER BY a; + +SELECT format(123456.789, 3, 'el_GR'); +DROP TABLE t1; + +--echo End of 5.4 tests diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index a98163e026c..e7d7d5ca16b 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -576,11 +576,11 @@ set lc_time_names=NULL; set lc_time_names=-1; select @@lc_time_names; --echo LC_TIME_NAMES: testing locale with the last ID: -set lc_time_names=108; +set lc_time_names=109; select @@lc_time_names; --echo LC_TIME_NAMES: testing a number beyond the valid ID range: --error ER_UNKNOWN_LOCALE -set lc_time_names=109; +set lc_time_names=110; select @@lc_time_names; --echo LC_TIME_NAMES: testing that 0 is en_US: set lc_time_names=0; diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index b59c3f16735..fcfd60e72e6 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -3009,6 +3009,77 @@ MY_LOCALE my_locale_zh_HK /***** LOCALE END zh_HK *****/ +/***** LOCALE BEGIN el_GR: Greek - Greece *****/ +static const char *my_locale_month_names_el_GR[13]= +{ + "ΙανουάÏιος", "ΦεβÏουάÏιος", "ΜάÏτιος", + "ΑπÏίλιος", "Μάιος", "ΙοÏνιος", + "ΙοÏλιος", "ΑÏγουστος", "ΣεπτέμβÏιος", + "ΟκτώβÏιος", "ÎοέμβÏιος", "ΔεκέμβÏιος", NullS +}; + +static const char *my_locale_ab_month_names_el_GR[13]= +{ + "Ιαν", "Φεβ", "ΜάÏ", + "ΑπÏ", "Μάι", "ΙοÏν", + "ΙοÏλ","ΑÏγ", "Σεπ", + "Οκτ", "Îοέ", "Δεκ", NullS +}; + +static const char *my_locale_day_names_el_GR[8] = +{ + "ΔευτέÏα", "ΤÏίτη", "ΤετάÏτη", "Πέμπτη", + "ΠαÏασκευή", "Σάββατο", "ΚυÏιακή", NullS +}; + +static const char *my_locale_ab_day_names_el_GR[8]= +{ + "Δευ", "ΤÏί", "Τετ", "Πέμ", + "ΠαÏ", "Σάβ", "ΚυÏ", NullS +}; + +static TYPELIB my_locale_typelib_month_names_el_GR= +{ + array_elements(my_locale_month_names_el_GR) - 1, + "", my_locale_month_names_el_GR, NULL +}; + +static TYPELIB my_locale_typelib_ab_month_names_el_GR= +{ + array_elements(my_locale_ab_month_names_el_GR)-1, + "", my_locale_ab_month_names_el_GR, NULL +}; + +static TYPELIB my_locale_typelib_day_names_el_GR= +{ + array_elements(my_locale_day_names_el_GR)-1, + "", my_locale_day_names_el_GR, NULL +}; + +static TYPELIB my_locale_typelib_ab_day_names_el_GR= +{ + array_elements(my_locale_ab_day_names_el_GR) - 1, + "", my_locale_ab_day_names_el_GR, NULL +}; + +MY_LOCALE my_locale_el_GR +( + 109, + "el_GR", + "Greek - Greece", + FALSE, + &my_locale_typelib_month_names_el_GR, + &my_locale_typelib_ab_month_names_el_GR, + &my_locale_typelib_day_names_el_GR, + &my_locale_typelib_ab_day_names_el_GR, + 11, /* max mon name length */ + 9, /* max day name length */ + ',', /* decimal point el_GR */ + '.', /* thousands_sep el_GR */ + "\x80" /* grouping el_GR */ +); +/***** LOCALE END el_GR *****/ + /* The list of all locales. Note, locales must be ordered according to their @@ -3126,6 +3197,7 @@ MY_LOCALE *my_locales[]= &my_locale_no_NO, &my_locale_sv_FI, &my_locale_zh_HK, + &my_locale_el_GR, NULL }; From f628035317b88cdd3afccc1b0177d81d22ccff55 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 6 Oct 2009 15:34:49 +0500 Subject: [PATCH 083/274] Bsckporting WL#3764 Sinhala Collation modified: mysql-test/r/ctype_utf8.result mysql-test/t/ctype_utf8.test mysys/charset-def.c strings/ctype-uca.c --- mysql-test/r/ctype_utf8.result | 112 +++++++++++++++++++++++++++++++++ mysql-test/t/ctype_utf8.test | 19 ++++++ mysys/charset-def.c | 4 ++ strings/ctype-uca.c | 93 +++++++++++++++++++++++++++ 4 files changed, 228 insertions(+) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 70f976ee9a7..393625f5192 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1880,3 +1880,115 @@ CONVERT(a, CHAR) CONVERT(b, CHAR) 70000 1092 DROP TABLE t1; End of 5.0 tests +Start of 5.4 tests +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +predicted_order int NOT NULL, +utf8_encoding VARCHAR(10) NOT NULL +) CHARACTER SET utf8; +INSERT INTO t1 VALUES (19, x'E0B696'), (30, x'E0B69AE0B798'), (61, x'E0B6AF'), (93, x'E0B799'), (52, x'E0B6A6'), (73, x'E0B6BBE0B78AE2808D'), (3, x'E0B686'), (56, x'E0B6AA'), (55, x'E0B6A9'), (70, x'E0B6B9'), (94, x'E0B79A'), (80, x'E0B785'), (25, x'E0B69AE0B791'), (48, x'E0B6A2'), (13, x'E0B690'), (86, x'E0B793'), (91, x'E0B79F'), (81, x'E0B786'), (79, x'E0B784'), (14, x'E0B691'), (99, x'E0B78A'), (8, x'E0B68B'), (68, x'E0B6B7'), (22, x'E0B69A'), (16, x'E0B693'), (33, x'E0B69AE0B7B3'), (38, x'E0B69AE0B79D'), (21, x'E0B683'), (11, x'E0B68E'), (77, x'E0B782'), (40, x'E0B69AE0B78A'), (101, x'E0B78AE2808DE0B6BB'), (35, x'E0B69AE0B79A'), (1, x'E0B7B4'), (9, x'E0B68C'), (96, x'E0B79C'), (6, x'E0B689'), (95, x'E0B79B'), (88, x'E0B796'), (64, x'E0B6B3'), (26, x'E0B69AE0B792'), (82, x'E0B78F'), (28, x'E0B69AE0B794'), (39, x'E0B69AE0B79E'), (97, x'E0B79D'), (2, x'E0B685'), (75, x'E0B780'), (34, x'E0B69AE0B799'), (69, x'E0B6B8'), (83, x'E0B790'), (18, x'E0B695'), (90, x'E0B7B2'), (17, x'E0B694'), (72, x'E0B6BB'), (66, x'E0B6B5'), (59, x'E0B6AD'), (44, x'E0B69E'), (15, x'E0B692'), (23, x'E0B69AE0B78F'), (65, x'E0B6B4'), (42, x'E0B69C'), (63, x'E0B6B1'), (85, x'E0B792'), (47, x'E0B6A1'), (49, x'E0B6A3'), (92, x'E0B7B3'), (78, x'E0B783'), (36, x'E0B69AE0B79B'), (4, x'E0B687'), (24, x'E0B69AE0B790'), (87, x'E0B794'), (37, x'E0B69AE0B79C'), (32, x'E0B69AE0B79F'), (29, x'E0B69AE0B796'), (43, x'E0B69D'), (62, x'E0B6B0'), (100, x'E0B78AE2808DE0B6BA'), (60, x'E0B6AE'), (45, x'E0B69F'), (12, x'E0B68F'), (46, x'E0B6A0'), (50, x'E0B6A5'), (51, x'E0B6A4'), (5, x'E0B688'), (76, x'E0B781'), (89, x'E0B798'), (74, x'E0B6BD'), (10, x'E0B68D'), (57, x'E0B6AB'), (71, x'E0B6BA'), (58, x'E0B6AC'), (27, x'E0B69AE0B793'), (54, x'E0B6A8'), (84, x'E0B791'), (31, x'E0B69AE0B7B2'), (98, x'E0B79E'), (53, x'E0B6A7'), (41, x'E0B69B'), (67, x'E0B6B6'), (7, x'E0B68A'), (20, x'E0B682'); +SELECT predicted_order, hex(utf8_encoding) FROM t1 ORDER BY utf8_encoding COLLATE utf8_sinhala_ci; +predicted_order hex(utf8_encoding) +1 E0B7B4 +2 E0B685 +3 E0B686 +4 E0B687 +5 E0B688 +6 E0B689 +7 E0B68A +8 E0B68B +9 E0B68C +10 E0B68D +11 E0B68E +12 E0B68F +13 E0B690 +14 E0B691 +15 E0B692 +16 E0B693 +17 E0B694 +18 E0B695 +19 E0B696 +20 E0B682 +21 E0B683 +22 E0B69A +23 E0B69AE0B78F +24 E0B69AE0B790 +25 E0B69AE0B791 +26 E0B69AE0B792 +27 E0B69AE0B793 +28 E0B69AE0B794 +29 E0B69AE0B796 +30 E0B69AE0B798 +31 E0B69AE0B7B2 +32 E0B69AE0B79F +33 E0B69AE0B7B3 +34 E0B69AE0B799 +35 E0B69AE0B79A +36 E0B69AE0B79B +37 E0B69AE0B79C +38 E0B69AE0B79D +39 E0B69AE0B79E +40 E0B69AE0B78A +41 E0B69B +42 E0B69C +43 E0B69D +44 E0B69E +45 E0B69F +46 E0B6A0 +47 E0B6A1 +48 E0B6A2 +49 E0B6A3 +50 E0B6A5 +51 E0B6A4 +52 E0B6A6 +53 E0B6A7 +54 E0B6A8 +55 E0B6A9 +56 E0B6AA +57 E0B6AB +58 E0B6AC +59 E0B6AD +60 E0B6AE +61 E0B6AF +62 E0B6B0 +63 E0B6B1 +64 E0B6B3 +65 E0B6B4 +66 E0B6B5 +67 E0B6B6 +68 E0B6B7 +69 E0B6B8 +70 E0B6B9 +71 E0B6BA +72 E0B6BB +73 E0B6BBE0B78AE2808D +74 E0B6BD +75 E0B780 +76 E0B781 +77 E0B782 +78 E0B783 +79 E0B784 +80 E0B785 +81 E0B786 +82 E0B78F +83 E0B790 +84 E0B791 +85 E0B792 +86 E0B793 +87 E0B794 +88 E0B796 +89 E0B798 +90 E0B7B2 +91 E0B79F +92 E0B7B3 +93 E0B799 +94 E0B79A +95 E0B79B +96 E0B79C +97 E0B79D +98 E0B79E +99 E0B78A +100 E0B78AE2808DE0B6BA +101 E0B78AE2808DE0B6BB +DROP TABLE t1; +End of 5.4 tests diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index f0c769251cf..7e93b638acb 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -1456,3 +1456,22 @@ SELECT CONVERT(a, CHAR), CONVERT(b, CHAR) from t1 GROUP BY b; DROP TABLE t1; --echo End of 5.0 tests + + +--echo Start of 5.4 tests +# +# Bug#26474: Add Sinhala script (Sri Lanka) collation to MySQL +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 ( + predicted_order int NOT NULL, + utf8_encoding VARCHAR(10) NOT NULL +) CHARACTER SET utf8; +INSERT INTO t1 VALUES (19, x'E0B696'), (30, x'E0B69AE0B798'), (61, x'E0B6AF'), (93, x'E0B799'), (52, x'E0B6A6'), (73, x'E0B6BBE0B78AE2808D'), (3, x'E0B686'), (56, x'E0B6AA'), (55, x'E0B6A9'), (70, x'E0B6B9'), (94, x'E0B79A'), (80, x'E0B785'), (25, x'E0B69AE0B791'), (48, x'E0B6A2'), (13, x'E0B690'), (86, x'E0B793'), (91, x'E0B79F'), (81, x'E0B786'), (79, x'E0B784'), (14, x'E0B691'), (99, x'E0B78A'), (8, x'E0B68B'), (68, x'E0B6B7'), (22, x'E0B69A'), (16, x'E0B693'), (33, x'E0B69AE0B7B3'), (38, x'E0B69AE0B79D'), (21, x'E0B683'), (11, x'E0B68E'), (77, x'E0B782'), (40, x'E0B69AE0B78A'), (101, x'E0B78AE2808DE0B6BB'), (35, x'E0B69AE0B79A'), (1, x'E0B7B4'), (9, x'E0B68C'), (96, x'E0B79C'), (6, x'E0B689'), (95, x'E0B79B'), (88, x'E0B796'), (64, x'E0B6B3'), (26, x'E0B69AE0B792'), (82, x'E0B78F'), (28, x'E0B69AE0B794'), (39, x'E0B69AE0B79E'), (97, x'E0B79D'), (2, x'E0B685'), (75, x'E0B780'), (34, x'E0B69AE0B799'), (69, x'E0B6B8'), (83, x'E0B790'), (18, x'E0B695'), (90, x'E0B7B2'), (17, x'E0B694'), (72, x'E0B6BB'), (66, x'E0B6B5'), (59, x'E0B6AD'), (44, x'E0B69E'), (15, x'E0B692'), (23, x'E0B69AE0B78F'), (65, x'E0B6B4'), (42, x'E0B69C'), (63, x'E0B6B1'), (85, x'E0B792'), (47, x'E0B6A1'), (49, x'E0B6A3'), (92, x'E0B7B3'), (78, x'E0B783'), (36, x'E0B69AE0B79B'), (4, x'E0B687'), (24, x'E0B69AE0B790'), (87, x'E0B794'), (37, x'E0B69AE0B79C'), (32, x'E0B69AE0B79F'), (29, x'E0B69AE0B796'), (43, x'E0B69D'), (62, x'E0B6B0'), (100, x'E0B78AE2808DE0B6BA'), (60, x'E0B6AE'), (45, x'E0B69F'), (12, x'E0B68F'), (46, x'E0B6A0'), (50, x'E0B6A5'), (51, x'E0B6A4'), (5, x'E0B688'), (76, x'E0B781'), (89, x'E0B798'), (74, x'E0B6BD'), (10, x'E0B68D'), (57, x'E0B6AB'), (71, x'E0B6BA'), (58, x'E0B6AC'), (27, x'E0B69AE0B793'), (54, x'E0B6A8'), (84, x'E0B791'), (31, x'E0B69AE0B7B2'), (98, x'E0B79E'), (53, x'E0B6A7'), (41, x'E0B69B'), (67, x'E0B6B6'), (7, x'E0B68A'), (20, x'E0B682'); +SELECT predicted_order, hex(utf8_encoding) FROM t1 ORDER BY utf8_encoding COLLATE utf8_sinhala_ci; +DROP TABLE t1; + +--echo End of 5.4 tests + diff --git a/mysys/charset-def.c b/mysys/charset-def.c index 63bbceef29b..bf2576621ce 100644 --- a/mysys/charset-def.c +++ b/mysys/charset-def.c @@ -42,6 +42,7 @@ extern CHARSET_INFO my_charset_ucs2_roman_uca_ci; extern CHARSET_INFO my_charset_ucs2_persian_uca_ci; extern CHARSET_INFO my_charset_ucs2_esperanto_uca_ci; extern CHARSET_INFO my_charset_ucs2_hungarian_uca_ci; +extern CHARSET_INFO my_charset_ucs2_sinhala_uca_ci; #endif #ifdef HAVE_CHARSET_utf8 @@ -63,6 +64,7 @@ extern CHARSET_INFO my_charset_utf8_roman_uca_ci; extern CHARSET_INFO my_charset_utf8_persian_uca_ci; extern CHARSET_INFO my_charset_utf8_esperanto_uca_ci; extern CHARSET_INFO my_charset_utf8_hungarian_uca_ci; +extern CHARSET_INFO my_charset_utf8_sinhala_uca_ci; #ifdef HAVE_UTF8_GENERAL_CS extern CHARSET_INFO my_charset_utf8_general_cs; #endif @@ -152,6 +154,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_ucs2_persian_uca_ci); add_compiled_collation(&my_charset_ucs2_esperanto_uca_ci); add_compiled_collation(&my_charset_ucs2_hungarian_uca_ci); + add_compiled_collation(&my_charset_ucs2_sinhala_uca_ci); #endif #endif @@ -186,6 +189,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf8_persian_uca_ci); add_compiled_collation(&my_charset_utf8_esperanto_uca_ci); add_compiled_collation(&my_charset_utf8_hungarian_uca_ci); + add_compiled_collation(&my_charset_utf8_sinhala_uca_ci); #endif #endif diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 566cc58ab0a..ecf92c1b7d4 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -6712,6 +6712,34 @@ static const char hungarian[]= "&O < \\u00F6 <<< \\u00D6 << \\u0151 <<< \\u0150" "&U < \\u00FC <<< \\u00DC << \\u0171 <<< \\u0170"; +/* + SCCII Part 1 : Collation Sequence (SLS1134) + 2006/11/24 + Harshula Jayasuriya + Language Technology Research Lab, University of Colombo / ICTA +*/ +#if 0 +static const char sinhala[]= + "& \\u0D96 < \\u0D82 < \\u0D83" + "& \\u0DA5 < \\u0DA4" + "& \\u0DD8 < \\u0DF2 < \\u0DDF < \\u0DF3" + "& \\u0DDE < \\u0DCA"; +#else +static const char sinhala[]= + "& \\u0D96 < \\u0D82 < \\u0D83 < \\u0D9A < \\u0D9B < \\u0D9C < \\u0D9D" + "< \\u0D9E < \\u0D9F < \\u0DA0 < \\u0DA1 < \\u0DA2 < \\u0DA3" + "< \\u0DA5 < \\u0DA4 < \\u0DA6" + "< \\u0DA7 < \\u0DA8 < \\u0DA9 < \\u0DAA < \\u0DAB < \\u0DAC" + "< \\u0DAD < \\u0DAE < \\u0DAF < \\u0DB0 < \\u0DB1" + "< \\u0DB3 < \\u0DB4 < \\u0DB5 < \\u0DB6 < \\u0DB7 < \\u0DB8" + "< \\u0DB9 < \\u0DBA < \\u0DBB < \\u0DBD < \\u0DC0 < \\u0DC1" + "< \\u0DC2 < \\u0DC3 < \\u0DC4 < \\u0DC5 < \\u0DC6" + "< \\u0DCF" + "< \\u0DD0 < \\u0DD1 < \\u0DD2 < \\u0DD3 < \\u0DD4 < \\u0DD6" + "< \\u0DD8 < \\u0DF2 < \\u0DDF < \\u0DF3 < \\u0DD9 < \\u0DDA" + "< \\u0DDB < \\u0DDC < \\u0DDD < \\u0DDE < \\u0DCA"; +#endif + /* Unicode Collation Algorithm: @@ -8698,6 +8726,39 @@ CHARSET_INFO my_charset_ucs2_hungarian_uca_ci= }; +CHARSET_INFO my_charset_ucs2_sinhala_uca_ci= +{ + 147,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + "ucs2", /* csname */ + "ucs2_sinhala_ci", /* name */ + "", /* comment */ + sinhala, /* tailoring */ + NULL, /* ctype */ + NULL, /* to_lower */ + NULL, /* to_upper */ + NULL, /* sort_order */ + NULL, /* contractions */ + NULL, /* sort_order_big*/ + NULL, /* tab_to_uni */ + NULL, /* tab_from_uni */ + my_unicase_default, /* caseinfo */ + NULL, /* state_map */ + NULL, /* ident_map */ + 8, /* strxfrm_multiply */ + 1, /* caseup_multiply */ + 1, /* casedn_multiply */ + 2, /* mbminlen */ + 2, /* mbmaxlen */ + 9, /* min_sort_char */ + 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ + 0, /* escape_with_backslash_is_dangerous */ + &my_charset_ucs2_handler, + &my_collation_ucs2_uca_handler +}; + + #endif @@ -9355,6 +9416,38 @@ CHARSET_INFO my_charset_utf8_hungarian_uca_ci= &my_collation_any_uca_handler }; +CHARSET_INFO my_charset_utf8_sinhala_uca_ci= +{ + 211,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + "utf8", /* cs name */ + "utf8_sinhala_ci", /* name */ + "", /* comment */ + sinhala, /* tailoring */ + ctype_utf8, /* ctype */ + NULL, /* to_lower */ + NULL, /* to_upper */ + NULL, /* sort_order */ + NULL, /* contractions */ + NULL, /* sort_order_big*/ + NULL, /* tab_to_uni */ + NULL, /* tab_from_uni */ + my_unicase_default, /* caseinfo */ + NULL, /* state_map */ + NULL, /* ident_map */ + 8, /* strxfrm_multiply */ + 1, /* caseup_multiply */ + 1, /* casedn_multiply */ + 3, /* mbminlen */ + 3, /* mbmaxlen */ + 9, /* min_sort_char */ + 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ + 0, /* escape_with_backslash_is_dangerous */ + &my_charset_utf8_handler, + &my_collation_any_uca_handler +}; + #endif /* HAVE_CHARSET_utf8 */ #endif /* HAVE_UCA_COLLATIONS */ From 068d170b3cf16e5b93a1f9a9b350613db427fa16 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Tue, 6 Oct 2009 14:47:04 +0400 Subject: [PATCH 084/274] Backport WL#4085: Merge revno:2476.657.219 from 6.0. --- mysql-test/mysql-test-run.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 17102196f42..78b69b26367 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -816,7 +816,6 @@ sub command_line_setup { 'combination=s' => \@opt_combinations, 'skip-combinations' => \&collect_option, 'experimental=s' => \$opt_experimental, - 'skip-im' => \&ignore_option, # Specify ports 'build-thread|mtr-build-thread=i' => \$opt_build_thread, From aea063c2dcf91213cfdefa282379a2f5da943325 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Tue, 6 Oct 2009 14:52:26 +0400 Subject: [PATCH 085/274] Backport WL#4085: Merge revno:2476.1105.1 from 6.0. --- server-tools/CMakeLists.txt | 33 - server-tools/Makefile.am | 20 - server-tools/instance-manager/CMakeLists.txt | 38 - server-tools/instance-manager/IMService.cpp | 124 -- server-tools/instance-manager/IMService.h | 32 - server-tools/instance-manager/Makefile.am | 103 - server-tools/instance-manager/README | 11 - .../instance-manager/WindowsService.cpp | 231 --- .../instance-manager/WindowsService.h | 56 - server-tools/instance-manager/angel.cc | 407 ---- server-tools/instance-manager/angel.h | 34 - server-tools/instance-manager/buffer.cc | 110 -- server-tools/instance-manager/buffer.h | 65 - server-tools/instance-manager/command.cc | 30 - server-tools/instance-manager/command.h | 60 - server-tools/instance-manager/commands.cc | 1752 ----------------- server-tools/instance-manager/commands.h | 393 ---- server-tools/instance-manager/exit_codes.h | 40 - server-tools/instance-manager/guardian.cc | 496 ----- server-tools/instance-manager/guardian.h | 110 -- server-tools/instance-manager/instance.cc | 944 --------- server-tools/instance-manager/instance.h | 273 --- server-tools/instance-manager/instance_map.cc | 649 ------ server-tools/instance-manager/instance_map.h | 102 - .../instance-manager/instance_options.cc | 753 ------- .../instance-manager/instance_options.h | 126 -- server-tools/instance-manager/listener.cc | 337 ---- server-tools/instance-manager/listener.h | 61 - server-tools/instance-manager/log.cc | 196 -- server-tools/instance-manager/log.h | 59 - server-tools/instance-manager/manager.cc | 526 ----- server-tools/instance-manager/manager.h | 71 - server-tools/instance-manager/messages.cc | 104 - server-tools/instance-manager/messages.h | 23 - .../instance-manager/mysql_connection.cc | 376 ---- .../instance-manager/mysql_connection.h | 74 - .../instance-manager/mysql_manager_error.h | 40 - server-tools/instance-manager/mysqlmanager.cc | 232 --- server-tools/instance-manager/options.cc | 558 ------ server-tools/instance-manager/options.h | 108 - server-tools/instance-manager/parse.cc | 509 ----- server-tools/instance-manager/parse.h | 212 -- server-tools/instance-manager/parse_output.cc | 407 ---- server-tools/instance-manager/parse_output.h | 33 - server-tools/instance-manager/portability.h | 65 - server-tools/instance-manager/priv.cc | 76 - server-tools/instance-manager/priv.h | 99 - server-tools/instance-manager/protocol.cc | 217 -- server-tools/instance-manager/protocol.h | 47 - .../instance-manager/thread_registry.cc | 419 ---- .../instance-manager/thread_registry.h | 176 -- .../user_management_commands.cc | 421 ---- .../user_management_commands.h | 167 -- server-tools/instance-manager/user_map.cc | 395 ---- server-tools/instance-manager/user_map.h | 103 - 55 files changed, 13103 deletions(-) delete mode 100644 server-tools/CMakeLists.txt delete mode 100644 server-tools/Makefile.am delete mode 100755 server-tools/instance-manager/CMakeLists.txt delete mode 100644 server-tools/instance-manager/IMService.cpp delete mode 100644 server-tools/instance-manager/IMService.h delete mode 100644 server-tools/instance-manager/Makefile.am delete mode 100644 server-tools/instance-manager/README delete mode 100644 server-tools/instance-manager/WindowsService.cpp delete mode 100644 server-tools/instance-manager/WindowsService.h delete mode 100644 server-tools/instance-manager/angel.cc delete mode 100644 server-tools/instance-manager/angel.h delete mode 100644 server-tools/instance-manager/buffer.cc delete mode 100644 server-tools/instance-manager/buffer.h delete mode 100644 server-tools/instance-manager/command.cc delete mode 100644 server-tools/instance-manager/command.h delete mode 100644 server-tools/instance-manager/commands.cc delete mode 100644 server-tools/instance-manager/commands.h delete mode 100644 server-tools/instance-manager/exit_codes.h delete mode 100644 server-tools/instance-manager/guardian.cc delete mode 100644 server-tools/instance-manager/guardian.h delete mode 100644 server-tools/instance-manager/instance.cc delete mode 100644 server-tools/instance-manager/instance.h delete mode 100644 server-tools/instance-manager/instance_map.cc delete mode 100644 server-tools/instance-manager/instance_map.h delete mode 100644 server-tools/instance-manager/instance_options.cc delete mode 100644 server-tools/instance-manager/instance_options.h delete mode 100644 server-tools/instance-manager/listener.cc delete mode 100644 server-tools/instance-manager/listener.h delete mode 100644 server-tools/instance-manager/log.cc delete mode 100644 server-tools/instance-manager/log.h delete mode 100644 server-tools/instance-manager/manager.cc delete mode 100644 server-tools/instance-manager/manager.h delete mode 100644 server-tools/instance-manager/messages.cc delete mode 100644 server-tools/instance-manager/messages.h delete mode 100644 server-tools/instance-manager/mysql_connection.cc delete mode 100644 server-tools/instance-manager/mysql_connection.h delete mode 100644 server-tools/instance-manager/mysql_manager_error.h delete mode 100644 server-tools/instance-manager/mysqlmanager.cc delete mode 100644 server-tools/instance-manager/options.cc delete mode 100644 server-tools/instance-manager/options.h delete mode 100644 server-tools/instance-manager/parse.cc delete mode 100644 server-tools/instance-manager/parse.h delete mode 100644 server-tools/instance-manager/parse_output.cc delete mode 100644 server-tools/instance-manager/parse_output.h delete mode 100644 server-tools/instance-manager/portability.h delete mode 100644 server-tools/instance-manager/priv.cc delete mode 100644 server-tools/instance-manager/priv.h delete mode 100644 server-tools/instance-manager/protocol.cc delete mode 100644 server-tools/instance-manager/protocol.h delete mode 100644 server-tools/instance-manager/thread_registry.cc delete mode 100644 server-tools/instance-manager/thread_registry.h delete mode 100644 server-tools/instance-manager/user_management_commands.cc delete mode 100644 server-tools/instance-manager/user_management_commands.h delete mode 100644 server-tools/instance-manager/user_map.cc delete mode 100644 server-tools/instance-manager/user_map.h diff --git a/server-tools/CMakeLists.txt b/server-tools/CMakeLists.txt deleted file mode 100644 index 3f02ba88f1d..00000000000 --- a/server-tools/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2006 MySQL AB -# -# 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 - -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - -ADD_DEFINITIONS(-DMYSQL_SERVER -DMYSQL_INSTANCE_MANAGER) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/sql - ${PROJECT_SOURCE_DIR}/extra/yassl/include) - -ADD_EXECUTABLE(mysqlmanager buffer.cc command.cc commands.cc guardian.cc instance.cc instance_map.cc - instance_options.cc listener.cc log.cc manager.cc messages.cc mysql_connection.cc - mysqlmanager.cc options.cc parse.cc parse_output.cc priv.cc protocol.cc - thread_registry.cc user_map.cc imservice.cpp windowsservice.cpp - user_management_commands.cc - ../../sql/net_serv.cc ../../sql-common/pack.c ../../sql/password.c - ../../sql/sql_state.c ../../sql-common/client.c ../../libmysql/get_password.c - ../../libmysql/errmsg.c) - -ADD_DEPENDENCIES(mysqlmanager GenError) -TARGET_LINK_LIBRARIES(mysqlmanager dbug mysys strings taocrypt vio yassl zlib wsock32) diff --git a/server-tools/Makefile.am b/server-tools/Makefile.am deleted file mode 100644 index 96e9d5a946e..00000000000 --- a/server-tools/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2003, 2006 MySQL AB -# -# 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 - -SUBDIRS = . instance-manager -DIST_SUBDIRS = . instance-manager - -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/server-tools/instance-manager/CMakeLists.txt b/server-tools/instance-manager/CMakeLists.txt deleted file mode 100755 index 2b9bce56ff7..00000000000 --- a/server-tools/instance-manager/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2006 MySQL AB -# -# 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 -INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") - -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - -ADD_DEFINITIONS(-DMYSQL_SERVER -DMYSQL_INSTANCE_MANAGER) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/sql - ${PROJECT_SOURCE_DIR}/extra/yassl/include) - -ADD_EXECUTABLE(mysqlmanager buffer.cc command.cc commands.cc guardian.cc instance.cc instance_map.cc - instance_options.cc listener.cc log.cc manager.cc messages.cc mysql_connection.cc - mysqlmanager.cc options.cc parse.cc parse_output.cc priv.cc protocol.cc - thread_registry.cc user_map.cc IMService.cpp WindowsService.cpp - user_management_commands.cc - ../../sql/net_serv.cc ../../sql-common/pack.c ../../sql/password.c - ../../sql/sql_state.c ../../sql-common/client.c ../../libmysql/get_password.c - ../../libmysql/errmsg.c) - -ADD_DEPENDENCIES(mysqlmanager GenError) -TARGET_LINK_LIBRARIES(mysqlmanager debug dbug mysys strings taocrypt vio yassl zlib wsock32) - -IF(EMBED_MANIFESTS) - MYSQL_EMBED_MANIFEST("mysqlmanager" "asInvoker") -ENDIF(EMBED_MANIFESTS) diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp deleted file mode 100644 index feccaadbecc..00000000000 --- a/server-tools/instance-manager/IMService.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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 */ - -#include -#include - -#include "IMService.h" - -#include "log.h" -#include "manager.h" -#include "options.h" - -static const char * const IM_SVC_USERNAME= NULL; -static const char * const IM_SVC_PASSWORD= NULL; - -IMService::IMService(void) - :WindowsService("MySqlManager", "MySQL Manager") -{ -} - -IMService::~IMService(void) -{ -} - -void IMService::Stop() -{ - ReportStatus(SERVICE_STOP_PENDING); - - /* stop the IM work */ - raise(SIGTERM); -} - -void IMService::Run(DWORD argc, LPTSTR *argv) -{ - /* report to the SCM that we're about to start */ - ReportStatus((DWORD)SERVICE_START_PENDING); - - Options::load(argc, argv); - - /* init goes here */ - ReportStatus((DWORD)SERVICE_RUNNING); - - /* wait for main loop to terminate */ - (void) Manager::main(); - Options::cleanup(); -} - -void IMService::Log(const char *msg) -{ - log_info(msg); -} - -int IMService::main() -{ - IMService winService; - - if (Options::Service::install_as_service) - { - if (winService.IsInstalled()) - { - log_info("Service is already installed."); - return 1; - } - - if (winService.Install(IM_SVC_USERNAME, IM_SVC_PASSWORD)) - { - log_info("Service installed successfully."); - return 0; - } - else - { - log_error("Service failed to install."); - return 1; - } - } - - if (Options::Service::remove_service) - { - if (!winService.IsInstalled()) - { - log_info("Service is not installed."); - return 1; - } - - if (winService.Remove()) - { - log_info("Service removed successfully."); - return 0; - } - else - { - log_error("Service failed to remove."); - return 1; - } - } - - log_info("Initializing Instance Manager service..."); - - if (!winService.Init()) - { - log_error("Service failed to initialize."); - - fprintf(stderr, - "The service should be started by Windows Service Manager.\n" - "The MySQL Manager should be started with '--standalone'\n" - "to run from command line."); - - return 1; - } - - return 0; -} diff --git a/server-tools/instance-manager/IMService.h b/server-tools/instance-manager/IMService.h deleted file mode 100644 index aceafb2fca6..00000000000 --- a/server-tools/instance-manager/IMService.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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 */ - -#pragma once -#include "WindowsService.h" - -class IMService: public WindowsService -{ -public: - static int main(); - -private: - IMService(void); - ~IMService(void); - -protected: - void Log(const char *msg); - void Stop(); - void Run(DWORD argc, LPTSTR *argv); -}; diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am deleted file mode 100644 index 19c4ac8de19..00000000000 --- a/server-tools/instance-manager/Makefile.am +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright (C) 2004 MySQL AB -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -INCLUDES= @ZLIB_INCLUDES@ -I$(top_srcdir)/include \ - @openssl_includes@ -I$(top_builddir)/include - -DEFS= -DMYSQL_INSTANCE_MANAGER -DMYSQL_SERVER - -# As all autoconf variables depend from ${prefix} and being resolved only when -# make is run, we can not put these defines to a header file (e.g. to -# default_options.h, generated from default_options.h.in) -# See automake/autoconf docs for details - -noinst_LTLIBRARIES= liboptions.la -noinst_LIBRARIES= libnet.a - -liboptions_la_CXXFLAGS= $(CXXFLAGS) \ - -DDEFAULT_PID_FILE_NAME="$(localstatedir)/mysqlmanager.pid" \ - -DDEFAULT_LOG_FILE_NAME="$(localstatedir)/mysqlmanager.log" \ - -DDEFAULT_SOCKET_FILE_NAME="/tmp/mysqlmanager.sock" \ - -DDEFAULT_PASSWORD_FILE_NAME="/etc/mysqlmanager.passwd" \ - -DDEFAULT_MYSQLD_PATH="$(libexecdir)/mysqld$(EXEEXT)" \ - -DDEFAULT_CONFIG_FILE="my.cnf" \ - -DPROTOCOL_VERSION=@PROTOCOL_VERSION@ - -liboptions_la_SOURCES= options.h options.cc priv.h priv.cc -liboptions_la_LIBADD= $(top_builddir)/libmysql/get_password.lo - -# MySQL sometimes uses symlinks to reuse code -# All symlinked files are grouped in libnet.a - -nodist_libnet_a_SOURCES= net_serv.cc client_settings.h -libnet_a_LIBADD= $(top_builddir)/sql/password.$(OBJEXT) \ - $(top_builddir)/sql/pack.$(OBJEXT) \ - $(top_builddir)/sql/sql_state.$(OBJEXT) \ - $(top_builddir)/sql/mini_client_errors.$(OBJEXT)\ - $(top_builddir)/sql/client.$(OBJEXT) - -CLEANFILES= net_serv.cc client_settings.h - -net_serv.cc: - rm -f net_serv.cc - @LN_CP_F@ $(top_srcdir)/sql/net_serv.cc net_serv.cc - -client_settings.h: - rm -f client_settings.h - @LN_CP_F@ $(top_srcdir)/sql/client_settings.h client_settings.h - -libexec_PROGRAMS= mysqlmanager - -mysqlmanager_CXXFLAGS= - -mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \ - manager.h manager.cc log.h log.cc \ - thread_registry.h thread_registry.cc \ - listener.h listener.cc protocol.h protocol.cc \ - mysql_connection.h mysql_connection.cc \ - user_map.h user_map.cc \ - messages.h messages.cc \ - commands.h commands.cc \ - instance.h instance.cc \ - instance_map.h instance_map.cc\ - instance_options.h instance_options.cc \ - buffer.h buffer.cc parse.cc parse.h \ - guardian.cc guardian.h \ - parse_output.cc parse_output.h \ - mysql_manager_error.h \ - portability.h \ - exit_codes.h \ - user_management_commands.h \ - user_management_commands.cc \ - angel.h \ - angel.cc - -mysqlmanager_LDADD= @CLIENT_EXTRA_LDFLAGS@ \ - liboptions.la \ - libnet.a \ - $(top_builddir)/vio/libvio.a \ - $(top_builddir)/mysys/libmysys.a \ - $(top_builddir)/strings/libmystrings.a \ - $(top_builddir)/dbug/libdbug.a \ - @openssl_libs@ @yassl_libs@ @ZLIB_LIBS@ - -EXTRA_DIST = WindowsService.cpp WindowsService.h IMService.cpp \ - IMService.h CMakeLists.txt - -tags: - ctags -R *.h *.cc - -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/server-tools/instance-manager/README b/server-tools/instance-manager/README deleted file mode 100644 index ac799775003..00000000000 --- a/server-tools/instance-manager/README +++ /dev/null @@ -1,11 +0,0 @@ -Instance Manager - manage MySQL instances locally and remotely. - -File description: - mysqlmanager.cc - entry point to the manager, main, - options.{h,cc} - handle startup options - manager.{h,cc} - manager process - mysql_connection.{h,cc} - handle one connection with mysql client. - -See also instance manager architecture description in mysqlmanager.cc. - - diff --git a/server-tools/instance-manager/WindowsService.cpp b/server-tools/instance-manager/WindowsService.cpp deleted file mode 100644 index 14795e2225a..00000000000 --- a/server-tools/instance-manager/WindowsService.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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 */ - -#include "my_global.h" -#include -#include "WindowsService.h" - -static WindowsService *gService; - -WindowsService::WindowsService(const char *p_serviceName, - const char *p_displayName) : - statusCheckpoint(0), - serviceName(p_serviceName), - displayName(p_displayName), - inited(FALSE), - dwAcceptedControls(SERVICE_ACCEPT_STOP), - debugging(FALSE) -{ - DBUG_ASSERT(serviceName != NULL); - - /* TODO: shouldn't we check displayName too (can it really be NULL)? */ - - /* WindowsService is assumed to be singleton. Let's assure this. */ - DBUG_ASSERT(gService == NULL); - - gService= this; - - status.dwServiceType= SERVICE_WIN32_OWN_PROCESS; - status.dwServiceSpecificExitCode= 0; -} - -WindowsService::~WindowsService(void) -{ -} - -BOOL WindowsService::Install(const char *username, const char *password) -{ - bool ret_val= FALSE; - SC_HANDLE newService; - SC_HANDLE scm; - - if (IsInstalled()) - return TRUE; - - // determine the name of the currently executing file - char szFilePath[_MAX_PATH]; - GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); - - // open a connection to the SCM - if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE))) - return FALSE; - - newService= CreateService(scm, serviceName, displayName, - SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - szFilePath, NULL, NULL, NULL, username, - password); - - if (newService) - { - CloseServiceHandle(newService); - ret_val= TRUE; - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::Init() -{ - DBUG_ASSERT(serviceName != NULL); - - if (inited) - return TRUE; - - SERVICE_TABLE_ENTRY stb[] = - { - { (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain}, - { NULL, NULL } - }; - inited= TRUE; - return StartServiceCtrlDispatcher(stb); //register with the Service Manager -} - -BOOL WindowsService::Remove() -{ - bool ret_val= FALSE; - - if (!IsInstalled()) - return TRUE; - - // open a connection to the SCM - SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE); - if (!scm) - return FALSE; - - SC_HANDLE service= OpenService(scm, serviceName, DELETE); - if (service) - { - if (DeleteService(service)) - ret_val= TRUE; - DWORD dw= ::GetLastError(); - CloseServiceHandle(service); - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::IsInstalled() -{ - BOOL ret_val= FALSE; - - SC_HANDLE scm= ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); - SC_HANDLE serv_handle= ::OpenService(scm, serviceName, SERVICE_QUERY_STATUS); - - ret_val= serv_handle != NULL; - - ::CloseServiceHandle(serv_handle); - ::CloseServiceHandle(scm); - - return ret_val; -} - -void WindowsService::SetAcceptedControls(DWORD acceptedControls) -{ - dwAcceptedControls= acceptedControls; -} - - -BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint, - DWORD dwError) -{ - if (debugging) - return TRUE; - - if(currentState == SERVICE_START_PENDING) - status.dwControlsAccepted= 0; - else - status.dwControlsAccepted= dwAcceptedControls; - - status.dwCurrentState= currentState; - status.dwWin32ExitCode= dwError != 0 ? - ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR; - status.dwWaitHint= waitHint; - status.dwServiceSpecificExitCode= dwError; - - if(currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED) - { - status.dwCheckPoint= 0; - statusCheckpoint= 0; - } - else - status.dwCheckPoint= ++statusCheckpoint; - - // Report the status of the service to the service control manager. - BOOL result= SetServiceStatus(statusHandle, &status); - if (!result) - Log("ReportStatus failed"); - - return result; -} - -void WindowsService::RegisterAndRun(DWORD argc, LPTSTR *argv) -{ - statusHandle= ::RegisterServiceCtrlHandler(serviceName, ControlHandler); - if (statusHandle && ReportStatus(SERVICE_START_PENDING)) - Run(argc, argv); - ReportStatus(SERVICE_STOPPED); -} - -void WindowsService::HandleControlCode(DWORD opcode) -{ - // Handle the requested control code. - switch(opcode) { - case SERVICE_CONTROL_STOP: - // Stop the service. - status.dwCurrentState= SERVICE_STOP_PENDING; - Stop(); - break; - - case SERVICE_CONTROL_PAUSE: - status.dwCurrentState= SERVICE_PAUSE_PENDING; - Pause(); - break; - - case SERVICE_CONTROL_CONTINUE: - status.dwCurrentState= SERVICE_CONTINUE_PENDING; - Continue(); - break; - - case SERVICE_CONTROL_SHUTDOWN: - Shutdown(); - break; - - case SERVICE_CONTROL_INTERROGATE: - ReportStatus(status.dwCurrentState); - break; - - default: - // invalid control code - break; - } -} - -void WINAPI WindowsService::ServiceMain(DWORD argc, LPTSTR *argv) -{ - DBUG_ASSERT(gService != NULL); - - // register our service control handler: - gService->RegisterAndRun(argc, argv); -} - -void WINAPI WindowsService::ControlHandler(DWORD opcode) -{ - DBUG_ASSERT(gService != NULL); - - return gService->HandleControlCode(opcode); -} diff --git a/server-tools/instance-manager/WindowsService.h b/server-tools/instance-manager/WindowsService.h deleted file mode 100644 index 02a499e5f0c..00000000000 --- a/server-tools/instance-manager/WindowsService.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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 */ - -#pragma once - -class WindowsService -{ -protected: - bool inited; - const char *serviceName; - const char *displayName; - SERVICE_STATUS_HANDLE statusHandle; - DWORD statusCheckpoint; - SERVICE_STATUS status; - DWORD dwAcceptedControls; - bool debugging; - -public: - WindowsService(const char *p_serviceName, const char *p_displayName); - ~WindowsService(void); - - BOOL Install(const char *username, const char *password); - BOOL Remove(); - BOOL Init(); - BOOL IsInstalled(); - void SetAcceptedControls(DWORD acceptedControls); - void Debug(bool debugFlag) { debugging= debugFlag; } - -public: - static void WINAPI ServiceMain(DWORD argc, LPTSTR *argv); - static void WINAPI ControlHandler(DWORD CtrlType); - -protected: - virtual void Run(DWORD argc, LPTSTR *argv)= 0; - virtual void Stop() {} - virtual void Shutdown() {} - virtual void Pause() {} - virtual void Continue() {} - virtual void Log(const char *msg) {} - - BOOL ReportStatus(DWORD currentStatus, DWORD waitHint= 3000, DWORD dwError=0); - void HandleControlCode(DWORD opcode); - void RegisterAndRun(DWORD argc, LPTSTR *argv); -}; diff --git a/server-tools/instance-manager/angel.cc b/server-tools/instance-manager/angel.cc deleted file mode 100644 index 64515c8498c..00000000000 --- a/server-tools/instance-manager/angel.cc +++ /dev/null @@ -1,407 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef __WIN__ - -#include "angel.h" - -#include -/* - sys/wait.h is needed for waitpid(). Unfortunately, there is no MySQL - include file, that can serve for this. Include it before MySQL system - headers so that we can change system defines if needed. -*/ - -#include "my_global.h" -#include "my_alarm.h" -#include "my_dir.h" -#include "my_sys.h" - -/* Include other IM files. */ - -#include "log.h" -#include "manager.h" -#include "options.h" -#include "priv.h" - -/************************************************************************/ - -enum { CHILD_OK= 0, CHILD_NEED_RESPAWN, CHILD_EXIT_ANGEL }; - -static int log_fd; - -static volatile sig_atomic_t child_status= CHILD_OK; -static volatile sig_atomic_t child_exit_code= 0; -static volatile sig_atomic_t shutdown_request_signo= 0; - - -/************************************************************************/ -/** - Open log file. - - @return - TRUE on error; - FALSE on success. -*************************************************************************/ - -static bool open_log_file() -{ - log_info("Angel: opening log file '%s'...", - (const char *) Options::Daemon::log_file_name); - - log_fd= open(Options::Daemon::log_file_name, - O_WRONLY | O_CREAT | O_APPEND | O_NOCTTY, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - - if (log_fd < 0) - { - log_error("Can not open log file '%s': %s.", - (const char *) Options::Daemon::log_file_name, - (const char *) strerror(errno)); - - return TRUE; - } - - return FALSE; -} - - -/************************************************************************/ -/** - Detach the process from controlling tty. - - @return - TRUE on error; - FALSE on success. -*************************************************************************/ - -static bool detach_process() -{ - /* - Become a session leader (the goal is not to have a controlling tty). - - setsid() must succeed because child is guaranteed not to be a process - group leader (it belongs to the process group of the parent). - - NOTE: if we now don't have a controlling tty we will not receive - tty-related signals - no need to ignore them. - */ - - if (setsid() < 0) - { - log_error("setsid() failed: %s.", (const char *) strerror(errno)); - return -1; - } - - /* Close STDIN. */ - - log_info("Angel: preparing standard streams."); - - if (close(STDIN_FILENO) < 0) - { - log_error("Warning: can not close stdin (%s)." - "Trying to continue...", - (const char *) strerror(errno)); - } - - /* Dup STDOUT and STDERR to the log file. */ - - if (dup2(log_fd, STDOUT_FILENO) < 0 || - dup2(log_fd, STDERR_FILENO) < 0) - { - log_error("Can not redirect stdout and stderr to the log file: %s.", - (const char *) strerror(errno)); - - return TRUE; - } - - if (log_fd != STDOUT_FILENO && log_fd != STDERR_FILENO) - { - if (close(log_fd) < 0) - { - log_error("Can not close original log file handler (%d): %s. " - "Trying to continue...", - (int) log_fd, - (const char *) strerror(errno)); - } - } - - return FALSE; -} - - -/************************************************************************/ -/** - Create PID file. - - @return - TRUE on error; - FALSE on success. -*************************************************************************/ - -static bool create_pid_file() -{ - if (create_pid_file(Options::Daemon::angel_pid_file_name, getpid())) - { - log_error("Angel: can not create pid file (%s).", - (const char *) Options::Daemon::angel_pid_file_name); - - return TRUE; - } - - log_info("Angel: pid file (%s) created.", - (const char *) Options::Daemon::angel_pid_file_name); - - return FALSE; -} - - -/************************************************************************/ -/** - SIGCHLD handler. - - Reap child, analyze child exit code, and set child_status - appropriately. -*************************************************************************/ - -extern "C" void reap_child(int); - -void reap_child(int __attribute__((unused)) signo) -{ - /* NOTE: As we have only one child, no need to cycle waitpid(). */ - - int exit_code; - - if (waitpid(0, &exit_code, WNOHANG) > 0) - { - child_exit_code= exit_code; - child_status= exit_code ? CHILD_NEED_RESPAWN : CHILD_EXIT_ANGEL; - } -} - - -/************************************************************************/ -/** - SIGTERM, SIGHUP, SIGINT handler. - - Set termination status and return. -*************************************************************************/ - -extern "C" void terminate(int signo); -void terminate(int signo) -{ - shutdown_request_signo= signo; -} - - -/************************************************************************/ -/** - Angel main loop. - - @return - The function returns exit status for global main(): - 0 -- program completed successfully; - !0 -- error occurred. -*************************************************************************/ - -static int angel_main_loop() -{ - /* - Install signal handlers. - - NOTE: Although signal handlers are needed only for parent process - (IM-angel), we should install them before fork() in order to avoid race - condition (i.e. to be sure, that IM-angel will receive SIGCHLD in any - case). - */ - - sigset_t wait_for_signals_mask; - - struct sigaction sa_chld; - struct sigaction sa_term; - struct sigaction sa_chld_orig; - struct sigaction sa_term_orig; - struct sigaction sa_int_orig; - struct sigaction sa_hup_orig; - - log_info("Angel: setting necessary signal actions..."); - - sigemptyset(&wait_for_signals_mask); - - sigemptyset(&sa_chld.sa_mask); - sa_chld.sa_handler= reap_child; - sa_chld.sa_flags= SA_NOCLDSTOP; - - sigemptyset(&sa_term.sa_mask); - sa_term.sa_handler= terminate; - sa_term.sa_flags= 0; - - /* NOTE: sigaction() fails only if arguments are wrong. */ - - sigaction(SIGCHLD, &sa_chld, &sa_chld_orig); - sigaction(SIGTERM, &sa_term, &sa_term_orig); - sigaction(SIGINT, &sa_term, &sa_int_orig); - sigaction(SIGHUP, &sa_term, &sa_hup_orig); - - /* The main Angel loop. */ - - while (true) - { - /* Spawn a new Manager. */ - - log_info("Angel: forking Manager process..."); - - switch (fork()) { - case -1: - log_error("Angel: can not fork IM-main: %s.", - (const char *) strerror(errno)); - - return -1; - - case 0: - /* - We are in child process, which will be IM-main: - - Restore default signal actions to let the IM-main work with - signals as he wishes; - - Call Manager::main(); - */ - - log_info("Angel: Manager process created successfully."); - - /* NOTE: sigaction() fails only if arguments are wrong. */ - - sigaction(SIGCHLD, &sa_chld_orig, NULL); - sigaction(SIGTERM, &sa_term_orig, NULL); - sigaction(SIGINT, &sa_int_orig, NULL); - sigaction(SIGHUP, &sa_hup_orig, NULL); - - log_info("Angel: executing Manager..."); - - return Manager::main(); - } - - /* Wait for signals. */ - - log_info("Angel: waiting for signals..."); - - while (child_status == CHILD_OK && shutdown_request_signo == 0) - sigsuspend(&wait_for_signals_mask); - - /* Exit if one of shutdown signals has been caught. */ - - if (shutdown_request_signo) - { - log_info("Angel: received shutdown signal (%d). Exiting...", - (int) shutdown_request_signo); - - return 0; - } - - /* Manager process died. Respawn it if it was a failure. */ - - if (child_status == CHILD_NEED_RESPAWN) - { - child_status= CHILD_OK; - - log_error("Angel: Manager exited abnormally (exit code: %d).", - (int) child_exit_code); - - log_info("Angel: sleeping 1 second..."); - - sleep(1); /* don't respawn too fast */ - - log_info("Angel: respawning Manager..."); - - continue; - } - - /* Delete IM-angel PID file. */ - - my_delete(Options::Daemon::angel_pid_file_name, MYF(0)); - - /* IM-angel finished. */ - - log_info("Angel: Manager exited normally. Exiting..."); - - return 0; - } -} - - -/************************************************************************/ -/** - Angel main function. - - @return - The function returns exit status for global main(): - 0 -- program completed successfully; - !0 -- error occurred. -*************************************************************************/ - -int Angel::main() -{ - log_info("Angel: started."); - - /* Open log file. */ - - if (open_log_file()) - return -1; - - /* Fork a new process. */ - - log_info("Angel: daemonizing..."); - - switch (fork()) { - case -1: - /* - This is the main Instance Manager process, fork() failed. - Log an error and bail out with error code. - */ - - log_error("fork() failed: %s.", (const char *) strerror(errno)); - return -1; - - case 0: - /* We are in child process. Continue Angel::main() execution. */ - - break; - - default: - /* - We are in the parent process. Return 0 so that parent exits - successfully. - */ - - log_info("Angel: exiting from the original process..."); - - return 0; - } - - /* Detach child from controlling tty. */ - - if (detach_process()) - return -1; - - /* Create PID file. */ - - if (create_pid_file()) - return -1; - - /* Start Angel main loop. */ - - return angel_main_loop(); -} - -#endif // __WIN__ diff --git a/server-tools/instance-manager/angel.h b/server-tools/instance-manager/angel.h deleted file mode 100644 index db21c250972..00000000000 --- a/server-tools/instance-manager/angel.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_ANGEL_H -#define INCLUDES_MYSQL_ANGEL_H - -#ifndef __WIN__ - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -#include - -class Angel -{ -public: - static int main(); -}; - -#endif // INCLUDES_MYSQL_ANGEL_H -#endif // __WIN__ diff --git a/server-tools/instance-manager/buffer.cc b/server-tools/instance-manager/buffer.cc deleted file mode 100644 index f197f42d009..00000000000 --- a/server-tools/instance-manager/buffer.cc +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "buffer.h" -#include - -const uint Buffer::BUFFER_INITIAL_SIZE= 4096; -const uint Buffer::MAX_BUFFER_SIZE= 16777216; - -/* - Puts the given string to the buffer. - - SYNOPSIS - append() - position start position in the buffer - string string to be put in the buffer - len_arg the length of the string. This way we can avoid some - strlens. - - DESCRIPTION - - The method puts a string into the buffer, starting from position . - In the case when the buffer is too small it reallocs the buffer. The - total size of the buffer is restricted with 16. - - RETURN - 0 - ok - 1 - got an error in reserve() -*/ - -int Buffer::append(size_t position, const char *string, size_t len_arg) -{ - if (reserve(position, len_arg)) - return 1; - - strnmov((char*) buffer + position, string, len_arg); - return 0; -} - - -/* - Checks whether the current buffer size is ok to put a string of the length - "len_arg" starting from "position" and reallocs it if no. - - SYNOPSIS - reserve() - position the number starting byte on the buffer to store a buffer - len_arg the length of the string. - - DESCRIPTION - - The method checks whether it is possible to put a string of the "len_arg" - length into the buffer, starting from "position" byte. In the case when the - buffer is too small it reallocs the buffer. The total size of the buffer is - restricted with 16 Mb. - - RETURN - 0 - ok - 1 - realloc error or we have come to the 16Mb barrier -*/ - -int Buffer::reserve(size_t position, size_t len_arg) -{ - if (position + len_arg >= MAX_BUFFER_SIZE) - goto err; - - if (position + len_arg >= buffer_size) - { - buffer= (uchar*) my_realloc(buffer, - min(MAX_BUFFER_SIZE, - max((uint) (buffer_size*1.5), - position + len_arg)), MYF(0)); - if (!(buffer)) - goto err; - buffer_size= (size_t) (buffer_size*1.5); - } - return 0; - -err: - error= 1; - return 1; -} - - -int Buffer::get_size() -{ - return (uint) buffer_size; -} - - -int Buffer::is_error() -{ - return error; -} diff --git a/server-tools/instance-manager/buffer.h b/server-tools/instance-manager/buffer.h deleted file mode 100644 index 3bd7a714437..00000000000 --- a/server-tools/instance-manager/buffer.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -/* - This class is a simple implementation of the buffer of varying size. - It is used to store MySQL client-server protocol packets. This is why - the maximum buffer size if 16Mb. (See internals manual section - 7. MySQL Client/Server Protocol) -*/ - -class Buffer -{ -private: - static const uint BUFFER_INITIAL_SIZE; - /* maximum buffer size is 16Mb */ - static const uint MAX_BUFFER_SIZE; - size_t buffer_size; - /* Error flag. Triggered if we get an error of some kind */ - int error; -public: - Buffer(size_t buffer_size_arg= BUFFER_INITIAL_SIZE) - :buffer_size(buffer_size_arg), error(0) - { - /* - As append() will invokes realloc() anyway, it's ok if malloc returns 0 - */ - if (!(buffer= (uchar*) my_malloc(buffer_size, MYF(0)))) - buffer_size= 0; - } - - ~Buffer() - { - my_free(buffer, MYF(0)); - } - -public: - uchar *buffer; - int get_size(); - int is_error(); - int append(size_t position, const char *string, size_t len_arg); - int reserve(size_t position, size_t len_arg); -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H */ diff --git a/server-tools/instance-manager/command.cc b/server-tools/instance-manager/command.cc deleted file mode 100644 index ba84285ead2..00000000000 --- a/server-tools/instance-manager/command.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "manager.h" -#include "command.h" - -Command::Command() - :guardian(Manager::get_guardian()), - instance_map(Manager::get_instance_map()) -{} - -Command::~Command() -{} - diff --git a/server-tools/instance-manager/command.h b/server-tools/instance-manager/command.h deleted file mode 100644 index 25d8c9849e8..00000000000 --- a/server-tools/instance-manager/command.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -/* Class responsible for allocation of IM commands. */ - -class Guardian; -class Instance_map; - -struct st_net; - -/* - Command - entry point for any command. - GangOf4: 'Command' design pattern -*/ - -class Command -{ -public: - Command(); - virtual ~Command(); - - /* - This operation incapsulates behaviour of the command. - - SYNOPSIS - net The network connection to the client. - connection_id Client connection ID - - RETURN - 0 On success - non 0 On error. Client error code is returned. - */ - virtual int execute(st_net *net, ulong connection_id) = 0; - -protected: - Guardian *guardian; - Instance_map *instance_map; -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H */ diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc deleted file mode 100644 index 56bd720b3e9..00000000000 --- a/server-tools/instance-manager/commands.cc +++ /dev/null @@ -1,1752 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "commands.h" - -#include -#include -#include -#include - -#include "buffer.h" -#include "guardian.h" -#include "instance_map.h" -#include "log.h" -#include "manager.h" -#include "messages.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "options.h" -#include "priv.h" -#include "protocol.h" - -/************************************************************************** - {{{ Static functions. -**************************************************************************/ - -/** - modify_defaults_to_im_error -- a map of error codes of - mysys::modify_defaults_file() into Instance Manager error codes. -*/ - -static const int modify_defaults_to_im_error[]= { 0, ER_OUT_OF_RESOURCES, - ER_ACCESS_OPTION_FILE }; - - -/** - Parse version number from the version string. - - SYNOPSIS - parse_version_number() - version_str - version - version_size - - DESCRIPTION - TODO - - TODO: Move this function to Instance_options and parse version number - only once. - - NOTE: This function is used only in SHOW INSTANCE STATUS statement at the - moment. -*/ - -static int parse_version_number(const char *version_str, char *version, - uint version_size) -{ - const char *start= version_str; - const char *end; - - // skip garbage - while (!my_isdigit(default_charset_info, *start)) - start++; - - end= start; - // skip digits and dots - while (my_isdigit(default_charset_info, *end) || *end == '.') - end++; - - if ((uint)(end - start) >= version_size) - return -1; - - strncpy(version, start, end-start); - version[end-start]= '\0'; - - return 0; -} - -/************************************************************************** - }}} -**************************************************************************/ - -/************************************************************************** - Implementation of Instance_name. -**************************************************************************/ - -Instance_name::Instance_name(const LEX_STRING *name) -{ - str.str= str_buffer; - str.length= name->length; - - if (str.length > MAX_INSTANCE_NAME_SIZE - 1) - str.length= MAX_INSTANCE_NAME_SIZE - 1; - - strmake(str.str, name->str, str.length); -} - -/************************************************************************** - Implementation of Show_instances. -**************************************************************************/ - -/** - Implementation of SHOW INSTANCES statement. - - Possible error codes: - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instances::execute(st_net *net, ulong /* connection_id */) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net))) - return err_code; - - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instances::write_header(st_net *net) -{ - LIST name, state; - LEX_STRING name_field, state_field; - LIST *field_list; - - name_field.str= (char *) "instance_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - state_field.str= (char *) "state"; - state_field.length= DEFAULT_FIELD_LENGTH; - state.data= &state_field; - - field_list= list_add(NULL, &state); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instances::write_data(st_net *net) -{ - my_bool err_status= FALSE; - - Instance *instance; - Instance_map::Iterator iterator(instance_map); - - instance_map->lock(); - - while ((instance= iterator.next())) - { - Buffer send_buf; /* buffer for packets */ - size_t pos= 0; - - instance->lock(); - - const char *instance_name= instance->options.instance_name.str; - const char *state_name= instance->get_state_name(); - - if (store_to_protocol_packet(&send_buf, instance_name, &pos) || - store_to_protocol_packet(&send_buf, state_name, &pos) || - my_net_write(net, send_buf.buffer, pos)) - { - err_status= TRUE; - } - - instance->unlock(); - - if (err_status) - break; - } - - instance_map->unlock(); - - return err_status ? ER_OUT_OF_RESOURCES : 0; -} - - -/************************************************************************** - Implementation of Flush_instances. -**************************************************************************/ - -/** - Implementation of FLUSH INSTANCES statement. - - Possible error codes: - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_THERE_IS_ACTIVE_INSTACE If there is an active instance -*/ - -int Flush_instances::execute(st_net *net, ulong connection_id) -{ - int err_status= Manager::flush_instances(); - - if (err_status) - return err_status; - - return net_send_ok(net, connection_id, NULL) ? ER_OUT_OF_RESOURCES : 0; -} - - -/************************************************************************** - Implementation of Instance_cmd. -**************************************************************************/ - -Instance_cmd::Instance_cmd(const LEX_STRING *instance_name_arg): - instance_name(instance_name_arg) -{ - /* - MT-NOTE: we can not make a search for Instance object here, - because it can dissappear after releasing the lock. - */ -} - - -/************************************************************************** - Implementation of Abstract_instance_cmd. -**************************************************************************/ - -Abstract_instance_cmd::Abstract_instance_cmd( - const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -int Abstract_instance_cmd::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - instance_map->lock(); - - instance= instance_map->find(get_instance_name()); - - if (!instance) - { - instance_map->unlock(); - return ER_BAD_INSTANCE_NAME; - } - - instance->lock(); - instance_map->unlock(); - - err_code= execute_impl(net, instance); - - instance->unlock(); - - if (!err_code) - err_code= send_ok_response(net, connection_id); - - return err_code; -} - - -/************************************************************************** - Implementation of Show_instance_status. -**************************************************************************/ - -Show_instance_status::Show_instance_status(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE STATUS statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_status::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_status::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_status::write_header(st_net *net) -{ - LIST name, state, version, version_number, mysqld_compatible; - LIST *field_list; - LEX_STRING name_field, state_field, version_field, - version_number_field, mysqld_compatible_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "instance_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - state_field.str= (char *) "state"; - state_field.length= DEFAULT_FIELD_LENGTH; - state.data= &state_field; - - version_field.str= (char *) "version"; - version_field.length= MAX_VERSION_LENGTH; - version.data= &version_field; - - version_number_field.str= (char *) "version_number"; - version_number_field.length= MAX_VERSION_LENGTH; - version_number.data= &version_number_field; - - mysqld_compatible_field.str= (char *) "mysqld_compatible"; - mysqld_compatible_field.length= DEFAULT_FIELD_LENGTH; - mysqld_compatible.data= &mysqld_compatible_field; - - field_list= list_add(NULL, &mysqld_compatible); - field_list= list_add(field_list, &version); - field_list= list_add(field_list, &version_number); - field_list= list_add(field_list, &state); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_status::write_data(st_net *net, Instance *instance) -{ - Buffer send_buf; /* buffer for packets */ - char version_num_buf[MAX_VERSION_LENGTH]; - size_t pos= 0; - - const char *state_name= instance->get_state_name(); - const char *version_tag= "unknown"; - const char *version_num= "unknown"; - const char *mysqld_compatible_status= - instance->is_mysqld_compatible() ? "yes" : "no"; - - if (instance->options.mysqld_version) - { - if (parse_version_number(instance->options.mysqld_version, version_num_buf, - sizeof(version_num_buf))) - return ER_OUT_OF_RESOURCES; - - version_num= version_num_buf; - version_tag= instance->options.mysqld_version; - } - - if (store_to_protocol_packet(&send_buf, get_instance_name()->str, &pos) || - store_to_protocol_packet(&send_buf, state_name, &pos) || - store_to_protocol_packet(&send_buf, version_num, &pos) || - store_to_protocol_packet(&send_buf, version_tag, &pos) || - store_to_protocol_packet(&send_buf, mysqld_compatible_status, &pos) || - my_net_write(net, send_buf.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Show_instance_options. -**************************************************************************/ - -Show_instance_options::Show_instance_options( - const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE OPTIONS statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_options::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_options::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_options::write_header(st_net *net) -{ - LIST name, option; - LIST *field_list; - LEX_STRING name_field, option_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "option_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - option_field.str= (char *) "value"; - option_field.length= DEFAULT_FIELD_LENGTH; - option.data= &option_field; - - field_list= list_add(NULL, &option); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_options::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - size_t pos= 0; - - if (store_to_protocol_packet(&send_buff, "instance_name", &pos) || - store_to_protocol_packet(&send_buff, get_instance_name()->str, &pos) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - /* Loop through the options. */ - - for (int i= 0; i < instance->options.get_num_options(); i++) - { - Named_value option= instance->options.get_option(i); - const char *option_value= option.get_value()[0] ? option.get_value() : ""; - - pos= 0; - - if (store_to_protocol_packet(&send_buff, option.get_name(), &pos) || - store_to_protocol_packet(&send_buff, option_value, &pos) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - } - - return 0; -} - - -/************************************************************************** - Implementation of Start_instance. -**************************************************************************/ - -Start_instance::Start_instance(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of START INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_INSTANCE_MISCONFIGURED The instance configuration is invalid - ER_INSTANCE_ALREADY_STARTED The instance is already started - ER_CANNOT_START_INSTANCE The instance could not have been started - - TODO: as soon as this method operates only with Instance, we probably - should introduce a new method (execute_stop_instance()) in Instance and - just call it from here. -*/ - -int Start_instance::execute_impl(st_net * /* net */, Instance *instance) -{ - if (!instance->is_configured()) - return ER_INSTANCE_MISCONFIGURED; - - if (instance->is_active()) - return ER_INSTANCE_ALREADY_STARTED; - - if (instance->start_mysqld()) - return ER_CANNOT_START_INSTANCE; - - instance->reset_stat(); - instance->set_state(Instance::NOT_STARTED); - - return 0; -} - - -int Start_instance::send_ok_response(st_net *net, ulong connection_id) -{ - if (net_send_ok(net, connection_id, "Instance started")) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation of Stop_instance. -**************************************************************************/ - -Stop_instance::Stop_instance(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of STOP INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - - TODO: as soon as this method operates only with Instance, we probably - should introduce a new method (execute_stop_instance()) in Instance and - just call it from here. -*/ - -int Stop_instance::execute_impl(st_net * /* net */, Instance *instance) -{ - if (!instance->is_active()) - return ER_INSTANCE_IS_NOT_STARTED; - - instance->set_state(Instance::STOPPED); - - return instance->stop_mysqld() ? ER_STOP_INSTANCE : 0; -} - - -int Stop_instance::send_ok_response(st_net *net, ulong connection_id) -{ - if (net_send_ok(net, connection_id, NULL)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Create_instance. -**************************************************************************/ - -Create_instance::Create_instance(const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -/** - This operation initializes Create_instance object. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing instance options. - - RETURN - FALSE On success. - TRUE On error. -*/ - -bool Create_instance::init(const char **text) -{ - return options.init() || parse_args(text); -} - - -/** - This operation parses CREATE INSTANCE options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing instance options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Create_instance::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return FALSE; /* OK: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING option_name; - char *option_name_str; - char *option_value_str= NULL; - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - /* Looking for equal sign. */ - - skip_spaces(text); - - if (**text == '=') - { - ++(*text); /* Skip an equal sign. */ - - /* Looking for option value. */ - - skip_spaces(text); - - if (!**text) - return TRUE; /* Syntax error: EOS when option value expected. */ - - if (**text != '\'' && **text != '"') - { - /* Option value is a simple token. */ - - LEX_STRING option_value; - - get_word(text, &option_value.length, ALPHANUM); - - if (option_value.length == 0) - return TRUE; /* internal parser error. */ - - option_value.str= (char *) *text; - *text+= option_value.length; - - if (!(option_value_str= Named_value::alloc_str(&option_value))) - return TRUE; /* out of memory during parsing. */ - } - else - { - /* Option value is a string. */ - - if (parse_option_value(*text, &len, &option_value_str)) - return TRUE; /* Syntax error: invalid string specification. */ - - *text+= len; - } - } - - if (!option_value_str) - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - return TRUE; /* out of memory during parsing. */ - } - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - { - Named_value::free_str(&option_value_str); - return TRUE; /* out of memory during parsing. */ - } - - { - Named_value option(option_name_str, option_value_str); - - if (options.add_element(&option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); - } -} - - -/** - Implementation of CREATE INSTANCE statement. - - Possible error codes: - ER_MALFORMED_INSTANCE_NAME Instance name is malformed - ER_CREATE_EXISTING_INSTANCE There is an instance with the given name - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Create_instance::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - /* Check that the name is valid and there is no instance with such name. */ - - if (!Instance::is_name_valid(get_instance_name())) - return ER_MALFORMED_INSTANCE_NAME; - - /* - NOTE: In order to prevent race condition, we should perform all operations - on under acquired lock. - */ - - instance_map->lock(); - - if (instance_map->find(get_instance_name())) - { - instance_map->unlock(); - return ER_CREATE_EXISTING_INSTANCE; - } - - if ((err_code= instance_map->create_instance(get_instance_name(), &options))) - { - instance_map->unlock(); - return err_code; - } - - instance= instance_map->find(get_instance_name()); - DBUG_ASSERT(instance); - - if ((err_code= create_instance_in_file(get_instance_name(), &options))) - { - instance_map->remove_instance(instance); /* instance is deleted here. */ - - instance_map->unlock(); - return err_code; - } - - /* - CREATE INSTANCE must not lead to start instance, even if it guarded. - - TODO: The problem however is that if Instance Manager restarts after - creating instance, the instance will be restarted (see also BUG#19718). - */ - - instance->set_state(Instance::STOPPED); - - /* That's all. */ - - instance_map->unlock(); - - /* Send the result. */ - - if (net_send_ok(net, connection_id, NULL)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Drop_instance. -**************************************************************************/ - -Drop_instance::Drop_instance(const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of DROP INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_DROP_ACTIVE_INSTANCE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Drop_instance::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - /* Lock Guardian, then Instance_map. */ - - instance_map->lock(); - - /* Find an instance. */ - - instance= instance_map->find(get_instance_name()); - - if (!instance) - { - instance_map->unlock(); - return ER_BAD_INSTANCE_NAME; - } - - instance->lock(); - - /* Check that the instance is offline. */ - - if (instance->is_active()) - { - instance->unlock(); - instance_map->unlock(); - - return ER_DROP_ACTIVE_INSTANCE; - } - - /* Try to remove instance from the file. */ - - err_code= modify_defaults_file(Options::Main::config_file, NULL, NULL, - get_instance_name()->str, MY_REMOVE_SECTION); - DBUG_ASSERT(err_code >= 0 && err_code <= 2); - - if (err_code) - { - log_error("Can not remove instance '%s' from defaults file (%s). " - "Original error code: %d.", - (const char *) get_instance_name()->str, - (const char *) Options::Main::config_file, - (int) err_code); - - instance->unlock(); - instance_map->unlock(); - - return modify_defaults_to_im_error[err_code]; - } - - /* Unlock the instance before destroy. */ - - instance->unlock(); - - /* - Remove instance from the instance map - (the instance will be also destroyed here). - */ - - instance_map->remove_instance(instance); - - /* Unlock the instance map. */ - - instance_map->unlock(); - - /* That's all: send ok. */ - - if (net_send_ok(net, connection_id, "Instance dropped")) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Show_instance_log. -**************************************************************************/ - -Show_instance_log::Show_instance_log(const LEX_STRING *instance_name_arg, - Log_type log_type_arg, - uint size_arg, uint offset_arg) - :Abstract_instance_cmd(instance_name_arg), - log_type(log_type_arg), - size(size_arg), - offset(offset_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE LOG statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OFFSET_ERROR We were requested to read negative number of - bytes from the log - ER_NO_SUCH_LOG The specified type of log is not available for - the given instance - ER_GUESS_LOGFILE IM wasn't able to figure out the log - placement, while it is enabled. Probably user - should specify the path to the logfile - explicitly. - ER_OPEN_LOGFILE Cannot open the logfile - ER_READ_FILE Cannot read the logfile - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_log::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= check_params(instance))) - return err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_log::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_log::check_params(Instance *instance) -{ - const char *logpath= instance->options.logs[log_type]; - - /* Cannot read negative number of bytes. */ - - if (offset > size) - return ER_OFFSET_ERROR; - - /* Instance has no such log. */ - - if (logpath == NULL) - return ER_NO_SUCH_LOG; - - if (*logpath == '\0') - return ER_GUESS_LOGFILE; - - return 0; -} - - -int Show_instance_log::write_header(st_net *net) -{ - LIST name; - LIST *field_list; - LEX_STRING name_field; - - /* Create list of the fields to be passed to send_fields(). */ - - name_field.str= (char *) "Log"; - name_field.length= DEFAULT_FIELD_LENGTH; - - name.data= &name_field; - - field_list= list_add(NULL, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_log::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - size_t pos= 0; - - const char *logpath= instance->options.logs[log_type]; - File fd; - - size_t buff_size; - size_t read_len; - - MY_STAT file_stat; - Buffer read_buff; - - if ((fd= my_open(logpath, O_RDONLY | O_BINARY, MYF(MY_WME))) <= 0) - return ER_OPEN_LOGFILE; - - /* my_fstat doesn't use the flag parameter */ - if (my_fstat(fd, &file_stat, MYF(0))) - { - close(fd); - return ER_OUT_OF_RESOURCES; - } - - /* calculate buffer size */ - buff_size= (size - offset); - - read_buff.reserve(0, buff_size); - - /* read in one chunk */ - read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0)); - - if ((read_len= my_read(fd, read_buff.buffer, buff_size, MYF(0))) == - MY_FILE_ERROR) - { - close(fd); - return ER_READ_FILE; - } - - close(fd); - - if (store_to_protocol_packet(&send_buff, (char*) read_buff.buffer, &pos, - read_len) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Show_instance_log_files. -**************************************************************************/ - -Show_instance_log_files::Show_instance_log_files - (const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE LOG FILES statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_log_files::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_log_files::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_log_files::write_header(st_net *net) -{ - LIST name, path, size; - LIST *field_list; - LEX_STRING name_field, path_field, size_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "Logfile"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - path_field.str= (char *) "Path"; - path_field.length= DEFAULT_FIELD_LENGTH; - path.data= &path_field; - - size_field.str= (char *) "File size"; - size_field.length= DEFAULT_FIELD_LENGTH; - size.data= &size_field; - - field_list= list_add(NULL, &size); - field_list= list_add(field_list, &path); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_log_files::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - - /* - We have alike structure in instance_options.cc. We use such to be able - to loop through the options, which we need to handle in some common way. - */ - struct log_files_st - { - const char *name; - const char *value; - } logs[]= - { - {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]}, - {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]}, - {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]}, - {NULL, NULL} - }; - struct log_files_st *log_files; - - for (log_files= logs; log_files->name; log_files++) - { - if (!log_files->value) - continue; - - struct stat file_stat; - /* - Save some more space for the log file names. In fact all - we need is strlen("GENERAL_LOG") + 1 - */ - enum { LOG_NAME_BUFFER_SIZE= 20 }; - char buff[LOG_NAME_BUFFER_SIZE]; - - size_t pos= 0; - - const char *log_path= ""; - const char *log_size= "0"; - - if (!stat(log_files->value, &file_stat) && - MY_S_ISREG(file_stat.st_mode)) - { - int10_to_str(file_stat.st_size, buff, 10); - - log_path= log_files->value; - log_size= buff; - } - - if (store_to_protocol_packet(&send_buff, log_files->name, &pos) || - store_to_protocol_packet(&send_buff, log_path, &pos) || - store_to_protocol_packet(&send_buff, log_size, &pos) || - my_net_write(net, send_buff.buffer, pos)) - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Abstract_option_cmd. -**************************************************************************/ - -/** - Instance_options_list -- a data class representing a list of options for - some instance. -*/ - -class Instance_options_list -{ -public: - Instance_options_list(const LEX_STRING *instance_name_arg); - -public: - bool init(); - - const LEX_STRING *get_instance_name() const - { - return instance_name.get_str(); - } - -public: - /* - This member is set and used only in Abstract_option_cmd::execute_impl(). - Normally it is not used (and should not). - - The problem is that construction and execution of commands are made not - in one transaction (not under one lock session). So, we can not initialize - instance in constructor and use it in execution. - */ - Instance *instance; - - Named_value_arr options; - -private: - Instance_name instance_name; -}; - - -/**************************************************************************/ - -Instance_options_list::Instance_options_list( - const LEX_STRING *instance_name_arg) - :instance(NULL), - instance_name(instance_name_arg) -{ -} - - -bool Instance_options_list::init() -{ - return options.init(); -} - - -/**************************************************************************/ - -C_MODE_START - -static uchar* get_item_key(const uchar* item, size_t* len, - my_bool __attribute__((unused)) t) -{ - const Instance_options_list *lst= (const Instance_options_list *) item; - *len= lst->get_instance_name()->length; - return (uchar *) lst->get_instance_name()->str; -} - -static void delete_item(void *item) -{ - delete (Instance_options_list *) item; -} - -C_MODE_END - - -/**************************************************************************/ - -Abstract_option_cmd::Abstract_option_cmd() - :initialized(FALSE) -{ -} - - -Abstract_option_cmd::~Abstract_option_cmd() -{ - if (initialized) - hash_free(&instance_options_map); -} - - -bool Abstract_option_cmd::add_option(const LEX_STRING *instance_name, - Named_value *option) -{ - Instance_options_list *lst= get_instance_options_list(instance_name); - - if (!lst) - return TRUE; - - lst->options.add_element(option); - - return FALSE; -} - - -bool Abstract_option_cmd::init(const char **text) -{ - static const int INITIAL_HASH_SIZE= 16; - - if (hash_init(&instance_options_map, default_charset_info, - INITIAL_HASH_SIZE, 0, 0, get_item_key, delete_item, 0)) - return TRUE; - - if (parse_args(text)) - return TRUE; - - initialized= TRUE; - - return FALSE; -} - - -/** - Correct the option file. The "skip" option is used to remove the found - option. - - SYNOPSIS - Abstract_option_cmd::correct_file() - skip Skip the option, being searched while writing the result file. - That is, to delete it. - - RETURN - 0 Success - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_ACCESS_OPTION_FILE Cannot access the option file -*/ - -int Abstract_option_cmd::correct_file(Instance *instance, Named_value *option, - bool skip) -{ - int err_code= modify_defaults_file(Options::Main::config_file, - option->get_name(), - option->get_value(), - instance->get_name()->str, - skip); - - DBUG_ASSERT(err_code >= 0 && err_code <= 2); - - if (err_code) - { - log_error("Can not modify option (%s) in defaults file (%s). " - "Original error code: %d.", - (const char *) option->get_name(), - (const char *) Options::Main::config_file, - (int) err_code); - } - - return modify_defaults_to_im_error[err_code]; -} - - -/** - Lock Instance Map and call execute_impl(). - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_INCOMPATIBLE_OPTION The specified option can not be set for - mysqld-compatible instance - ER_INSTANCE_IS_ACTIVE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Abstract_option_cmd::execute(st_net *net, ulong connection_id) -{ - int err_code; - - instance_map->lock(); - - err_code= execute_impl(net, connection_id); - - instance_map->unlock(); - - return err_code; -} - - -Instance_options_list * -Abstract_option_cmd::get_instance_options_list(const LEX_STRING *instance_name) -{ - Instance_options_list *lst= - (Instance_options_list *) hash_search(&instance_options_map, - (uchar *) instance_name->str, - instance_name->length); - - if (!lst) - { - lst= new Instance_options_list(instance_name); - - if (!lst) - return NULL; - - if (lst->init() || my_hash_insert(&instance_options_map, (uchar *) lst)) - { - delete lst; - return NULL; - } - } - - return lst; -} - - -/** - Skeleton implementation of option-management command. - - MT-NOTE: Instance Map is locked before calling this operation. -*/ -int Abstract_option_cmd::execute_impl(st_net *net, ulong connection_id) -{ - int err_code= 0; - - /* Check that all the specified instances exist and are offline. */ - - for (uint i= 0; i < instance_options_map.records; ++i) - { - Instance_options_list *lst= - (Instance_options_list *) hash_element(&instance_options_map, i); - - bool instance_is_active; - - lst->instance= instance_map->find(lst->get_instance_name()); - - if (!lst->instance) - return ER_BAD_INSTANCE_NAME; - - lst->instance->lock(); - instance_is_active= lst->instance->is_active(); - lst->instance->unlock(); - - if (instance_is_active) - return ER_INSTANCE_IS_ACTIVE; - } - - /* Perform command-specific (SET/UNSET) actions. */ - - for (uint i= 0; i < instance_options_map.records; ++i) - { - Instance_options_list *lst= - (Instance_options_list *) hash_element(&instance_options_map, i); - - lst->instance->lock(); - - for (int j= 0; j < lst->options.get_size(); ++j) - { - Named_value option= lst->options.get_element(j); - err_code= process_option(lst->instance, &option); - - if (err_code) - break; - } - - lst->instance->unlock(); - - if (err_code) - break; - } - - if (err_code == 0) - net_send_ok(net, connection_id, NULL); - - return err_code; -} - - -/************************************************************************** - Implementation of Set_option. -**************************************************************************/ - -/** - This operation parses SET options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Set_option::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return TRUE; /* Syntax error: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING instance_name; - LEX_STRING option_name; - char *option_name_str; - char *option_value_str= NULL; - - /* Looking for instance name. */ - - get_word(text, &instance_name.length, ALPHANUM); - - if (instance_name.length == 0) - return TRUE; /* Syntax error: instance name expected. */ - - instance_name.str= (char *) *text; - *text+= instance_name.length; - - skip_spaces(text); - - /* Check the the delimiter is a dot. */ - - if (**text != '.') - return TRUE; /* Syntax error: dot expected. */ - - ++(*text); - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - /* Looking for equal sign. */ - - skip_spaces(text); - - if (**text == '=') - { - ++(*text); /* Skip an equal sign. */ - - /* Looking for option value. */ - - skip_spaces(text); - - if (!**text) - return TRUE; /* Syntax error: EOS when option value expected. */ - - if (**text != '\'' && **text != '"') - { - /* Option value is a simple token. */ - - LEX_STRING option_value; - - get_word(text, &option_value.length, ALPHANUM); - - if (option_value.length == 0) - return TRUE; /* internal parser error. */ - - option_value.str= (char *) *text; - *text+= option_value.length; - - if (!(option_value_str= Named_value::alloc_str(&option_value))) - return TRUE; /* out of memory during parsing. */ - } - else - { - /* Option value is a string. */ - - if (parse_option_value(*text, &len, &option_value_str)) - return TRUE; /* Syntax error: invalid string specification. */ - - *text+= len; - } - } - - if (!option_value_str) - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - return TRUE; /* out of memory during parsing. */ - } - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - { - Named_value::free_str(&option_name_str); - return TRUE; /* out of memory during parsing. */ - } - - { - Named_value option(option_name_str, option_value_str); - - if (add_option(&instance_name, &option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); /* Skip a comma. */ - } -} - - -int Set_option::process_option(Instance *instance, Named_value *option) -{ - /* Check that the option is valid. */ - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option->get_name())) - { - log_error("IM-option (%s) can not be used " - "in the configuration of mysqld-compatible instance (%s).", - (const char *) option->get_name(), - (const char *) instance->get_name()->str); - return ER_INCOMPATIBLE_OPTION; - } - - /* Update the configuration file. */ - - int err_code= correct_file(instance, option, FALSE); - - if (err_code) - return err_code; - - /* Update the internal cache. */ - - if (instance->options.set_option(option)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation of Unset_option. -**************************************************************************/ - -/** - This operation parses UNSET options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Unset_option::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return TRUE; /* Syntax error: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING instance_name; - LEX_STRING option_name; - char *option_name_str; - char *option_value_str; - - /* Looking for instance name. */ - - get_word(text, &instance_name.length, ALPHANUM); - - if (instance_name.length == 0) - return TRUE; /* Syntax error: instance name expected. */ - - instance_name.str= (char *) *text; - *text+= instance_name.length; - - skip_spaces(text); - - /* Check the the delimiter is a dot. */ - - if (**text != '.') - return TRUE; /* Syntax error: dot expected. */ - - ++(*text); /* Skip a dot. */ - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - return TRUE; /* out of memory during parsing. */ - - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - { - Named_value::free_str(&option_name_str); - return TRUE; - } - } - - { - Named_value option(option_name_str, option_value_str); - - if (add_option(&instance_name, &option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); /* Skip a comma. */ - } -} - - -/** - Implementation of UNSET statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance name specified is not valid - ER_INSTANCE_IS_ACTIVE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Unset_option::process_option(Instance *instance, Named_value *option) -{ - /* Update the configuration file. */ - - int err_code= correct_file(instance, option, TRUE); - - if (err_code) - return err_code; - - /* Update the internal cache. */ - - instance->options.unset_option(option->get_name()); - - return 0; -} - - -/************************************************************************** - Implementation of Syntax_error. -**************************************************************************/ - -int Syntax_error::execute(st_net * /* net */, ulong /* connection_id */) -{ - return ER_SYNTAX_ERROR; -} diff --git a/server-tools/instance-manager/commands.h b/server-tools/instance-manager/commands.h deleted file mode 100644 index 5c2b2f9bbb7..00000000000 --- a/server-tools/instance-manager/commands.h +++ /dev/null @@ -1,393 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include -#include -#include - -#include "command.h" -#include "instance.h" -#include "parse.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - - -/** - Print all instances of this instance manager. - Grammar: SHOW INSTANCES -*/ - -class Show_instances: public Command -{ -public: - Show_instances() - { } - -public: - int execute(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net); -}; - - -/** - Reread configuration file and refresh internal cache. - Grammar: FLUSH INSTANCES -*/ - -class Flush_instances: public Command -{ -public: - Flush_instances() - { } - -public: - int execute(st_net *net, ulong connection_id); -}; - - -/** - Base class for Instance-specific commands - (commands that operate on one instance). - - Instance_cmd extends Command class by: - - an attribute for storing instance name; - - code to initialize instance name in constructor; - - an accessor to get instance name. -*/ - -class Instance_cmd : public Command -{ -public: - Instance_cmd(const LEX_STRING *instance_name_arg); - -protected: - inline const LEX_STRING *get_instance_name() const - { - return instance_name.get_str(); - } - -private: - Instance_name instance_name; -}; - - -/** - Abstract class for Instance-specific commands. - - Abstract_instance_cmd extends Instance_cmd by providing a common - framework for writing command-implementations. Basically, the class - implements Command::execute() pure virtual function in the following - way: - - Lock Instance_map; - - Get an instance by name. Return an error, if there is no such - instance; - - Lock the instance; - - Unlock Instance_map; - - Call execute_impl(), which should be implemented in derived class; - - Unlock the instance; - - Send response to the client and return error status. -*/ - -class Abstract_instance_cmd: public Instance_cmd -{ -public: - Abstract_instance_cmd(const LEX_STRING *instance_name_arg); - -public: - virtual int execute(st_net *net, ulong connection_id); - -protected: - /** - This operation is intended to contain command-specific implementation. - - MT-NOTE: this operation is called under acquired Instance's lock. - */ - virtual int execute_impl(st_net *net, Instance *instance) = 0; - - /** - This operation is invoked on successful return of execute_impl() and is - intended to send closing data. - - MT-NOTE: this operation is called under released Instance's lock. - */ - virtual int send_ok_response(st_net *net, ulong connection_id) = 0; -}; - - -/** - Print status of an instance. - Grammar: SHOW INSTANCE STATUS -*/ - -class Show_instance_status: public Abstract_instance_cmd -{ -public: - Show_instance_status(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); -}; - - -/** - Print options of chosen instance. - Grammar: SHOW INSTANCE OPTIONS -*/ - -class Show_instance_options: public Abstract_instance_cmd -{ -public: - Show_instance_options(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); -}; - - -/** - Start an instance. - Grammar: START INSTANCE -*/ - -class Start_instance: public Abstract_instance_cmd -{ -public: - Start_instance(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); -}; - - -/** - Stop an instance. - Grammar: STOP INSTANCE -*/ - -class Stop_instance: public Abstract_instance_cmd -{ -public: - Stop_instance(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); -}; - - -/** - Create an instance. - Grammar: CREATE INSTANCE [] -*/ - -class Create_instance: public Instance_cmd -{ -public: - Create_instance(const LEX_STRING *instance_name_arg); - -public: - bool init(const char **text); - -protected: - virtual int execute(st_net *net, ulong connection_id); - -private: - bool parse_args(const char **text); - -private: - Named_value_arr options; -}; - - -/** - Drop an instance. - Grammar: DROP INSTANCE - - Operation is permitted only if the instance is stopped. On successful - completion the instance section is removed from config file and the instance - is removed from the instance map. -*/ - -class Drop_instance: public Instance_cmd -{ -public: - Drop_instance(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute(st_net *net, ulong connection_id); -}; - - -/** - Print requested part of the log. - Grammar: - SHOW LOG {ERROR | SLOW | GENERAL} size[, offset_from_end] -*/ - -class Show_instance_log: public Abstract_instance_cmd -{ -public: - Show_instance_log(const LEX_STRING *instance_name_arg, - Log_type log_type_arg, uint size_arg, uint offset_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int check_params(Instance *instance); - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); - -private: - Log_type log_type; - uint size; - uint offset; -}; - - -/** - Shows the list of the log files, used by an instance. - Grammar: SHOW LOG FILES -*/ - -class Show_instance_log_files: public Abstract_instance_cmd -{ -public: - Show_instance_log_files(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); -}; - - -/** - Abstract class for option-management commands. -*/ - -class Instance_options_list; - -class Abstract_option_cmd: public Command -{ -public: - ~Abstract_option_cmd(); - -public: - bool add_option(const LEX_STRING *instance_name, Named_value *option); - -public: - bool init(const char **text); - - virtual int execute(st_net *net, ulong connection_id); - -protected: - Abstract_option_cmd(); - - int correct_file(Instance *instance, Named_value *option, bool skip); - -protected: - virtual bool parse_args(const char **text) = 0; - virtual int process_option(Instance *instance, Named_value *option) = 0; - -private: - Instance_options_list * - get_instance_options_list(const LEX_STRING *instance_name); - - int execute_impl(st_net *net, ulong connection_id); - -private: - HASH instance_options_map; - bool initialized; -}; - - -/** - Set an option for the instance. - Grammar: SET instance_name.option[=option_value][, ...] -*/ - -class Set_option: public Abstract_option_cmd -{ -public: - Set_option() - { } - -protected: - virtual bool parse_args(const char **text); - virtual int process_option(Instance *instance, Named_value *option); -}; - - -/** - Remove option of the instance. - Grammar: UNSET instance_name.option[, ...] -*/ - -class Unset_option: public Abstract_option_cmd -{ -public: - Unset_option() - { } - -protected: - virtual bool parse_args(const char **text); - virtual int process_option(Instance *instance, Named_value *option); -}; - - -/** - Syntax error command. - - This command is issued if parser reported a syntax error. We need it to - distinguish between syntax error and internal parser error. E.g. parsing - failed because we hadn't had enought memory. In the latter case the parser - just returns NULL. -*/ - -class Syntax_error: public Command -{ -public: - Syntax_error() - { } - -public: - int execute(st_net *net, ulong connection_id); -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */ diff --git a/server-tools/instance-manager/exit_codes.h b/server-tools/instance-manager/exit_codes.h deleted file mode 100644 index 1609debd8f9..00000000000 --- a/server-tools/instance-manager/exit_codes.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H - -/* - Copyright (C) 2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - This file contains a list of exit codes, which are used when Instance - Manager is working in user-management mode. -*/ - -const int ERR_OK = 0; - -const int ERR_OUT_OF_MEMORY = 1; -const int ERR_INVALID_USAGE = 2; -const int ERR_INTERNAL_ERROR = 3; -const int ERR_IO_ERROR = 4; -const int ERR_PASSWORD_FILE_CORRUPTED = 5; -const int ERR_PASSWORD_FILE_DOES_NOT_EXIST = 6; - -const int ERR_CAN_NOT_READ_USER_NAME = 10; -const int ERR_CAN_NOT_READ_PASSWORD = 11; -const int ERR_USER_ALREADY_EXISTS = 12; -const int ERR_USER_NOT_FOUND = 13; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc deleted file mode 100644 index b49b0ec0a00..00000000000 --- a/server-tools/instance-manager/guardian.cc +++ /dev/null @@ -1,496 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "guardian.h" -#include -#include -#include - -#include "instance.h" -#include "instance_map.h" -#include "log.h" -#include "mysql_manager_error.h" -#include "options.h" - - -/************************************************************************* - {{{ Constructor & destructor. -*************************************************************************/ - -/** - Guardian constructor. - - SYNOPSIS - Guardian() - thread_registry_arg - instance_map_arg - - DESCRIPTION - Nominal contructor intended for assigning references and initialize - trivial objects. Real initialization is made by init() method. -*/ - -Guardian::Guardian(Thread_registry *thread_registry_arg, - Instance_map *instance_map_arg) - :shutdown_requested(FALSE), - stopped(FALSE), - thread_registry(thread_registry_arg), - instance_map(instance_map_arg) -{ - pthread_mutex_init(&LOCK_guardian, 0); - pthread_cond_init(&COND_guardian, 0); -} - - -Guardian::~Guardian() -{ - /* - NOTE: it's necessary to synchronize here, because Guiardian thread can be - still alive an hold the mutex (because it is detached and we have no - control over it). - */ - - lock(); - unlock(); - - pthread_mutex_destroy(&LOCK_guardian); - pthread_cond_destroy(&COND_guardian); -} - -/************************************************************************* - }}} -*************************************************************************/ - - -/** - Send request to stop Guardian. - - SYNOPSIS - request_shutdown() -*/ - -void Guardian::request_shutdown() -{ - stop_instances(); - - lock(); - shutdown_requested= TRUE; - unlock(); - - ping(); -} - - -/** - Process an instance. - - SYNOPSIS - process_instance() - instance a pointer to the instance for processing - - MT-NOTE: - - the given instance must be locked before calling this operation; - - Guardian must be locked before calling this operation. -*/ - -void Guardian::process_instance(Instance *instance) -{ - int restart_retry= 100; - time_t current_time= time(NULL); - - if (instance->get_state() == Instance::STOPPING) - { - /* This brach is executed during shutdown. */ - - /* This returns TRUE if and only if an instance was stopped for sure. */ - if (instance->is_crashed()) - { - log_info("Guardian: '%s' stopped.", - (const char *) instance->get_name()->str); - - instance->set_state(Instance::STOPPED); - } - else if ((uint) (current_time - instance->last_checked) >= - instance->options.get_shutdown_delay()) - { - log_info("Guardian: '%s' hasn't stopped within %d secs.", - (const char *) instance->get_name()->str, - (int) instance->options.get_shutdown_delay()); - - instance->kill_mysqld(SIGKILL); - - log_info("Guardian: pretend that '%s' is killed.", - (const char *) instance->get_name()->str); - - instance->set_state(Instance::STOPPED); - } - else - { - log_info("Guardian: waiting for '%s' to stop (%d secs left).", - (const char *) instance->get_name()->str, - (int) (instance->options.get_shutdown_delay() - - current_time + instance->last_checked)); - } - - return; - } - - if (instance->is_mysqld_running()) - { - /* The instance can be contacted on it's port */ - - /* If STARTING also check that pidfile has been created */ - if (instance->get_state() == Instance::STARTING && - instance->options.load_pid() == 0) - { - /* Pid file not created yet, don't go to STARTED state yet */ - } - else if (instance->get_state() != Instance::STARTED) - { - /* clear status fields */ - log_info("Guardian: '%s' is running, set state to STARTED.", - (const char *) instance->options.instance_name.str); - instance->reset_stat(); - instance->set_state(Instance::STARTED); - } - } - else - { - switch (instance->get_state()) { - case Instance::NOT_STARTED: - log_info("Guardian: starting '%s'...", - (const char *) instance->options.instance_name.str); - - /* NOTE: set state to STARTING _before_ start() is called. */ - instance->set_state(Instance::STARTING); - instance->last_checked= current_time; - - instance->start_mysqld(); - - return; - - case Instance::STARTED: /* fallthrough */ - case Instance::STARTING: /* let the instance start or crash */ - if (!instance->is_crashed()) - return; - - instance->crash_moment= current_time; - instance->last_checked= current_time; - instance->set_state(Instance::JUST_CRASHED); - /* fallthrough -- restart an instance immediately */ - - case Instance::JUST_CRASHED: - if (current_time - instance->crash_moment <= 2) - { - if (instance->is_crashed()) - { - instance->start_mysqld(); - log_info("Guardian: starting '%s'...", - (const char *) instance->options.instance_name.str); - } - } - else - instance->set_state(Instance::CRASHED); - - return; - - case Instance::CRASHED: /* just regular restarts */ - if ((ulong) (current_time - instance->last_checked) <= - (ulong) Options::Main::monitoring_interval) - return; - - if (instance->restart_counter < restart_retry) - { - if (instance->is_crashed()) - { - instance->start_mysqld(); - instance->last_checked= current_time; - - log_info("Guardian: restarting '%s'...", - (const char *) instance->options.instance_name.str); - } - } - else - { - log_info("Guardian: can not start '%s'. " - "Abandoning attempts to (re)start it", - (const char *) instance->options.instance_name.str); - - instance->set_state(Instance::CRASHED_AND_ABANDONED); - } - - return; - - case Instance::CRASHED_AND_ABANDONED: - return; /* do nothing */ - - default: - DBUG_ASSERT(0); - } - } -} - - -/** - Main function of Guardian thread. - - SYNOPSIS - run() - - DESCRIPTION - Check for all guarded instances and restart them if needed. -*/ - -void Guardian::run() -{ - struct timespec timeout; - - log_info("Guardian: started."); - - thread_registry->register_thread(&thread_info); - - /* Loop, until all instances were shut down at the end. */ - - while (true) - { - Instance_map::Iterator instances_it(instance_map); - Instance *instance; - bool all_instances_stopped= TRUE; - - instance_map->lock(); - - while ((instance= instances_it.next())) - { - instance->lock(); - - if (!instance->is_guarded() || - instance->get_state() == Instance::STOPPED) - { - instance->unlock(); - continue; - } - - process_instance(instance); - - if (instance->get_state() != Instance::STOPPED) - all_instances_stopped= FALSE; - - instance->unlock(); - } - - instance_map->unlock(); - - lock(); - - if (shutdown_requested && all_instances_stopped) - { - log_info("Guardian: all guarded mysqlds stopped."); - - stopped= TRUE; - unlock(); - break; - } - - set_timespec(timeout, Options::Main::monitoring_interval); - - thread_registry->cond_timedwait(&thread_info, &COND_guardian, - &LOCK_guardian, &timeout); - unlock(); - } - - log_info("Guardian: stopped."); - - /* Now, when the Guardian is stopped we can stop the IM. */ - - thread_registry->unregister_thread(&thread_info); - thread_registry->request_shutdown(); - - log_info("Guardian: finished."); -} - - -/** - Return the value of stopped flag. -*/ - -bool Guardian::is_stopped() -{ - int var; - - lock(); - var= stopped; - unlock(); - - return var; -} - - -/** - Wake up Guardian thread. - - MT-NOTE: though usually the mutex associated with condition variable should - be acquired before signalling the variable, here this is not needed. - Signalling under locked mutex is used to avoid lost signals. In the current - logic however locking mutex does not guarantee that the signal will not be - lost. -*/ - -void Guardian::ping() -{ - pthread_cond_signal(&COND_guardian); -} - - -/** - Prepare list of instances. - - SYNOPSIS - init() - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -void Guardian::init() -{ - Instance *instance; - Instance_map::Iterator iterator(instance_map); - - while ((instance= iterator.next())) - { - instance->lock(); - - instance->reset_stat(); - instance->set_state(Instance::NOT_STARTED); - - instance->unlock(); - } -} - - -/** - An internal method which is called at shutdown to unregister instances and - attempt to stop them if requested. - - SYNOPSIS - stop_instances() - - DESCRIPTION - Loops through the guarded_instances list and prepares them for shutdown. - For each instance we issue a stop command and change the state - accordingly. - - NOTE - Guardian object should be locked by the caller. - -*/ - -void Guardian::stop_instances() -{ - static const int NUM_STOP_ATTEMPTS = 100; - - Instance_map::Iterator instances_it(instance_map); - Instance *instance; - - instance_map->lock(); - - while ((instance= instances_it.next())) - { - instance->lock(); - - if (!instance->is_guarded() || - instance->get_state() == Instance::STOPPED) - { - instance->unlock(); - continue; - } - - /* - If instance is running or was running (and now probably hanging), - request stop. - */ - - if (instance->is_mysqld_running() || - instance->get_state() == Instance::STARTED) - { - instance->set_state(Instance::STOPPING); - instance->last_checked= time(NULL); - } - else - { - /* Otherwise mark it as STOPPED. */ - instance->set_state(Instance::STOPPED); - } - - /* Request mysqld to stop. */ - - bool instance_stopped= FALSE; - - for (int cur_attempt= 0; cur_attempt < NUM_STOP_ATTEMPTS; ++cur_attempt) - { - if (!instance->kill_mysqld(SIGTERM)) - { - instance_stopped= TRUE; - break; - } - - if (!instance->is_active()) - { - instance_stopped= TRUE; - break; - } - - /* Sleep for 0.3 sec and check again. */ - - my_sleep(300000); - } - - /* - Abort if we failed to stop mysqld instance. That should not happen, - but if it happened, we don't know what to do and prefer to have clear - failure with coredump. - */ - - DBUG_ASSERT(instance_stopped); - - instance->unlock(); - } - - instance_map->unlock(); -} - - -/** - Lock Guardian. -*/ - -void Guardian::lock() -{ - pthread_mutex_lock(&LOCK_guardian); -} - - -/** - Unlock Guardian. -*/ - -void Guardian::unlock() -{ - pthread_mutex_unlock(&LOCK_guardian); -} diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h deleted file mode 100644 index d78058a6fc5..00000000000 --- a/server-tools/instance-manager/guardian.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - - -#include -#include -#include - -#include "thread_registry.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Instance; -class Instance_map; -class Thread_registry; - -/** - The guardian thread is responsible for monitoring and restarting of guarded - instances. -*/ - -class Guardian: public Thread -{ -public: - Guardian(Thread_registry *thread_registry_arg, - Instance_map *instance_map_arg); - ~Guardian(); - - void init(); - -public: - void request_shutdown(); - - bool is_stopped(); - - void lock(); - void unlock(); - - void ping(); - -protected: - virtual void run(); - -private: - void stop_instances(); - - void process_instance(Instance *instance); - -private: - /* - LOCK_guardian protectes the members in this section: - - shutdown_requested; - - stopped; - - Also, it is used for COND_guardian. - */ - pthread_mutex_t LOCK_guardian; - - /* - Guardian's main loop waits on this condition. So, it should be signalled - each time, when instance state has been changed and we want Guardian to - wake up. - - TODO: Change this to having data-scoped conditions, i.e. conditions, - which indicate that some data has been changed. - */ - pthread_cond_t COND_guardian; - - /* - This variable is set to TRUE, when Manager thread is shutting down. - The flag is used by Guardian thread to understand that it's time to - finish. - */ - bool shutdown_requested; - - /* - This flag is set to TRUE on shutdown by Guardian thread, when all guarded - mysqlds are stopped. - - The flag is used in the Manager thread to wait for Guardian to stop all - mysqlds. - */ - bool stopped; - - Thread_info thread_info; - Thread_registry *thread_registry; - Instance_map *instance_map; - -private: - Guardian(const Guardian &); - Guardian&operator =(const Guardian &); -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */ diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc deleted file mode 100644 index 1ad728d40eb..00000000000 --- a/server-tools/instance-manager/instance.cc +++ /dev/null @@ -1,944 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include -#include - -#include -#ifndef __WIN__ -#include -#endif - -#include "manager.h" -#include "guardian.h" -#include "instance.h" -#include "log.h" -#include "mysql_manager_error.h" -#include "portability.h" -#include "priv.h" -#include "thread_registry.h" -#include "instance_map.h" - - -/************************************************************************* - {{{ Platform-specific functions. -*************************************************************************/ - -#ifndef __WIN__ -typedef pid_t My_process_info; -#else -typedef PROCESS_INFORMATION My_process_info; -#endif - -/* - Wait for an instance - - SYNOPSIS - wait_process() - pi Pointer to the process information structure - (platform-dependent). - - RETURN - 0 - Success - 1 - Error -*/ - -#ifndef __WIN__ -static int wait_process(My_process_info *pi) -{ - /* - Here we wait for the child created. This process differs for systems - running LinuxThreads and POSIX Threads compliant systems. This is because - according to POSIX we could wait() for a child in any thread of the - process. While LinuxThreads require that wait() is called by the thread, - which created the child. - On the other hand we could not expect mysqld to return the pid, we - got in from fork(), to wait4() fucntion when running on LinuxThreads. - This is because MySQL shutdown thread is not the one, which was created - by our fork() call. - So basically we have two options: whether the wait() call returns only in - the creator thread, but we cannot use waitpid() since we have no idea - which pid we should wait for (in fact it should be the pid of shutdown - thread, but we don't know this one). Or we could use waitpid(), but - couldn't use wait(), because it could return in any wait() in the program. - */ - - if (Manager::is_linux_threads()) - wait(NULL); /* LinuxThreads were detected */ - else - waitpid(*pi, NULL, 0); - - return 0; -} -#else -static int wait_process(My_process_info *pi) -{ - /* Wait until child process exits. */ - WaitForSingleObject(pi->hProcess, INFINITE); - - DWORD exitcode; - ::GetExitCodeProcess(pi->hProcess, &exitcode); - - /* Close process and thread handles. */ - CloseHandle(pi->hProcess); - CloseHandle(pi->hThread); - - /* - GetExitCodeProces returns zero on failure. We should revert this value - to report an error. - */ - return (!exitcode); -} -#endif - -/* - Launch an instance - - SYNOPSIS - start_process() - instance_options Pointer to the options of the instance to be - launched. - pi Pointer to the process information structure - (platform-dependent). - - RETURN - FALSE - Success - TRUE - Cannot create an instance -*/ - -#ifndef __WIN__ -static bool start_process(Instance_options *instance_options, - My_process_info *pi) -{ -#ifndef __QNX__ - *pi= fork(); -#else - /* - On QNX one cannot use fork() in multithreaded environment and we - should use spawn() or one of it's siblings instead. - Here we use spawnv(), which is a combination of fork() and execv() - in one call. It returns the pid of newly created process (>0) or -1 - */ - *pi= spawnv(P_NOWAIT, instance_options->mysqld_path, instance_options->argv); -#endif - - switch (*pi) { - case 0: /* never happens on QNX */ - execv(instance_options->mysqld_path.str, instance_options->argv); - /* exec never returns */ - exit(1); - case -1: - log_error("Instance '%s': can not start mysqld: fork() failed.", - (const char *) instance_options->instance_name.str); - return TRUE; - } - - return FALSE; -} -#else -static bool start_process(Instance_options *instance_options, - My_process_info *pi) -{ - STARTUPINFO si; - - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb= sizeof(STARTUPINFO); - ZeroMemory(pi, sizeof(PROCESS_INFORMATION)); - - int cmdlen= 0; - for (int i= 0; instance_options->argv[i] != 0; i++) - cmdlen+= (uint) strlen(instance_options->argv[i]) + 3; - cmdlen++; /* make room for the null */ - - char *cmdline= new char[cmdlen]; - if (cmdline == NULL) - return TRUE; - - cmdline[0]= 0; - for (int i= 0; instance_options->argv[i] != 0; i++) - { - strcat(cmdline, "\""); - strcat(cmdline, instance_options->argv[i]); - strcat(cmdline, "\" "); - } - - /* Start the child process */ - BOOL result= - CreateProcess(NULL, /* Put it all in cmdline */ - cmdline, /* Command line */ - NULL, /* Process handle not inheritable */ - NULL, /* Thread handle not inheritable */ - FALSE, /* Set handle inheritance to FALSE */ - 0, /* No creation flags */ - NULL, /* Use parent's environment block */ - NULL, /* Use parent's starting directory */ - &si, /* Pointer to STARTUPINFO structure */ - pi); /* Pointer to PROCESS_INFORMATION structure */ - delete cmdline; - - return !result; -} -#endif - -#ifdef __WIN__ - -BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) -{ - DWORD dwTID, dwCode, dwErr= 0; - HANDLE hProcessDup= INVALID_HANDLE_VALUE; - HANDLE hRT= NULL; - HINSTANCE hKernel= GetModuleHandle("Kernel32"); - BOOL bSuccess= FALSE; - - BOOL bDup= DuplicateHandle(GetCurrentProcess(), - hProcess, GetCurrentProcess(), &hProcessDup, - PROCESS_ALL_ACCESS, FALSE, 0); - - // Detect the special case where the process is - // already dead... - if (GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) && - (dwCode == STILL_ACTIVE)) - { - FARPROC pfnExitProc; - - pfnExitProc= GetProcAddress(hKernel, "ExitProcess"); - - hRT= CreateRemoteThread((bDup) ? hProcessDup : hProcess, NULL, 0, - (LPTHREAD_START_ROUTINE)pfnExitProc, - (PVOID)uExitCode, 0, &dwTID); - - if (hRT == NULL) - dwErr= GetLastError(); - } - else - dwErr= ERROR_PROCESS_ABORTED; - - if (hRT) - { - // Must wait process to terminate to - // guarantee that it has exited... - WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE); - - CloseHandle(hRT); - bSuccess= TRUE; - } - - if (bDup) - CloseHandle(hProcessDup); - - if (!bSuccess) - SetLastError(dwErr); - - return bSuccess; -} - -int kill(pid_t pid, int signum) -{ - HANDLE processhandle= ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (signum == SIGTERM) - ::SafeTerminateProcess(processhandle, 0); - else - ::TerminateProcess(processhandle, -1); - return 0; -} -#endif - -/************************************************************************* - }}} -*************************************************************************/ - - -/************************************************************************* - {{{ Static constants. -*************************************************************************/ - -const LEX_STRING -Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_LEN("mysqld") }; - -/************************************************************************* - }}} -*************************************************************************/ - - -/************************************************************************* - {{{ Instance Monitor thread. -*************************************************************************/ - -/** - Proxy thread is a simple way to avoid all pitfalls of the threads - implementation in the OS (e.g. LinuxThreads). With such a thread we - don't have to process SIGCHLD, which is a tricky business if we want - to do it in a portable way. - - Instance Monitor Thread forks a child process, execs mysqld and waits for - the child to die. - - Instance Monitor assumes that the monitoring instance will not be dropped. - This is guaranteed by having flag monitoring_thread_active and - Instance::is_active() operation. -*/ - -class Instance_monitor: public Thread -{ -public: - Instance_monitor(Instance *instance_arg) :instance(instance_arg) {} -protected: - virtual void run(); - void start_and_monitor_instance(); -private: - Instance *instance; -}; - - -void Instance_monitor::run() -{ - start_and_monitor_instance(); - delete this; -} - - -void Instance_monitor::start_and_monitor_instance() -{ - Thread_registry *thread_registry= Manager::get_thread_registry(); - Guardian *guardian= Manager::get_guardian(); - - My_process_info mysqld_process_info; - Thread_info monitor_thread_info; - - log_info("Instance '%s': Monitor: started.", - (const char *) instance->get_name()->str); - - /* - For guarded instance register the thread in Thread_registry to wait for - the thread to stop on shutdown (nonguarded instances are not stopped on - shutdown, so the thread will no finish). - */ - - if (instance->is_guarded()) - { - thread_registry->register_thread(&monitor_thread_info, FALSE); - } - - /* Starting mysqld. */ - - log_info("Instance '%s': Monitor: starting mysqld...", - (const char *) instance->get_name()->str); - - if (start_process(&instance->options, &mysqld_process_info)) - { - instance->lock(); - instance->monitoring_thread_active= FALSE; - instance->unlock(); - - return; - } - - /* Waiting for mysqld to die. */ - - log_info("Instance '%s': Monitor: waiting for mysqld to stop...", - (const char *) instance->get_name()->str); - - wait_process(&mysqld_process_info); /* Don't check for return value. */ - - log_info("Instance '%s': Monitor: mysqld stopped.", - (const char *) instance->get_name()->str); - - /* Update instance status. */ - - instance->lock(); - - if (instance->is_guarded()) - thread_registry->unregister_thread(&monitor_thread_info); - - instance->crashed= TRUE; - instance->monitoring_thread_active= FALSE; - - log_info("Instance '%s': Monitor: finished.", - (const char *) instance->get_name()->str); - - instance->unlock(); - - /* Wake up guardian. */ - - guardian->ping(); -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Static operations. -**************************************************************************/ - -/** - The operation is intended to check whether string is a well-formed - instance name or not. - - SYNOPSIS - is_name_valid() - name string to check - - RETURN - TRUE string is a valid instance name - FALSE string is not a valid instance name - - TODO: Move to Instance_name class: Instance_name::is_valid(). -*/ - -bool Instance::is_name_valid(const LEX_STRING *name) -{ - const char *name_suffix= name->str + DFLT_INSTANCE_NAME.length; - - if (strncmp(name->str, Instance::DFLT_INSTANCE_NAME.str, - Instance::DFLT_INSTANCE_NAME.length) != 0) - return FALSE; - - return *name_suffix == 0 || my_isdigit(default_charset_info, *name_suffix); -} - - -/** - The operation is intended to check if the given instance name is - mysqld-compatible or not. - - SYNOPSIS - is_mysqld_compatible_name() - name name to check - - RETURN - TRUE name is mysqld-compatible - FALSE otherwise - - TODO: Move to Instance_name class: Instance_name::is_mysqld_compatible(). -*/ - -bool Instance::is_mysqld_compatible_name(const LEX_STRING *name) -{ - return strcmp(name->str, DFLT_INSTANCE_NAME.str) == 0; -} - - -/** - Return client state name. Must not be used outside the class. - Use Instance::get_state_name() instead. -*/ - -const char * Instance::get_instance_state_name(enum_instance_state state) -{ - switch (state) { - case STOPPED: - return "offline"; - - case NOT_STARTED: - return "not started"; - - case STARTING: - return "starting"; - - case STARTED: - return "online"; - - case JUST_CRASHED: - return "failed"; - - case CRASHED: - return "crashed"; - - case CRASHED_AND_ABANDONED: - return "abandoned"; - - case STOPPING: - return "stopping"; - } - - return NULL; /* just to ignore compiler warning. */ -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Initialization & deinitialization. -**************************************************************************/ - -Instance::Instance() - :monitoring_thread_active(FALSE), - crashed(FALSE), - configured(FALSE), - /* mysqld_compatible is initialized in init() */ - state(NOT_STARTED), - restart_counter(0), - crash_moment(0), - last_checked(0) -{ - pthread_mutex_init(&LOCK_instance, 0); -} - - -Instance::~Instance() -{ - log_info("Instance '%s': destroying...", (const char *) get_name()->str); - - pthread_mutex_destroy(&LOCK_instance); -} - - -/** - Initialize instance options. - - SYNOPSIS - init() - name_arg name of the instance - - RETURN: - FALSE - ok - TRUE - error -*/ - -bool Instance::init(const LEX_STRING *name_arg) -{ - mysqld_compatible= is_mysqld_compatible_name(name_arg); - - return options.init(name_arg); -} - - -/** - @brief Complete instance options initialization. - - @return Error status. - @retval FALSE ok - @retval TRUE error -*/ - -bool Instance::complete_initialization() -{ - configured= ! options.complete_initialization(); - return !configured; -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Instance: public interface implementation. -**************************************************************************/ - -/** - Determine if there is some activity with the instance. - - SYNOPSIS - is_active() - - DESCRIPTION - An instance is active if one of the following conditions is true: - - Instance-monitoring thread is running; - - Instance is guarded and its state is other than STOPPED; - - Corresponding mysqld-server accepts connections. - - MT-NOTE: instance must be locked before calling the operation. - - RETURN - TRUE - instance is active - FALSE - otherwise. -*/ - -bool Instance::is_active() -{ - if (monitoring_thread_active) - return TRUE; - - if (is_guarded() && get_state() != STOPPED) - return TRUE; - - return is_mysqld_running(); -} - - -/** - Determine if mysqld is accepting connections. - - SYNOPSIS - is_mysqld_running() - - DESCRIPTION - Try to connect to mysqld with fake login/password to check whether it is - accepting connections or not. - - MT-NOTE: instance must be locked before calling the operation. - - RETURN - TRUE - mysqld is alive and accept connections - FALSE - otherwise. -*/ - -bool Instance::is_mysqld_running() -{ - MYSQL mysql; - uint port= options.get_mysqld_port(); /* 0 if not specified. */ - const char *socket= NULL; - static const char *password= "check_connection"; - static const char *username= "MySQL_Instance_Manager"; - static const char *access_denied_message= "Access denied for user"; - bool return_val; - - if (options.mysqld_socket) - socket= options.mysqld_socket; - - /* no port was specified => instance falled back to default value */ - if (!port && !options.mysqld_socket) - port= SERVER_DEFAULT_PORT; - - mysql_init(&mysql); - /* try to connect to a server with a fake username/password pair */ - if (mysql_real_connect(&mysql, LOCAL_HOST, username, - password, - NullS, port, - socket, 0)) - { - /* - We have successfully connected to the server using fake - username/password. Write a warning to the logfile. - */ - log_error("Instance '%s': was able to log into mysqld.", - (const char *) get_name()->str); - return_val= TRUE; /* server is alive */ - } - else - return_val= test(!strncmp(access_denied_message, mysql_error(&mysql), - sizeof(access_denied_message) - 1)); - - mysql_close(&mysql); - - return return_val; -} - - -/** - @brief Start mysqld. - - Reset flags and start Instance Monitor thread, which will start mysqld. - - @note Instance must be locked before calling the operation. - - @return Error status code - @retval FALSE Ok - @retval TRUE Could not start instance -*/ - -bool Instance::start_mysqld() -{ - Instance_monitor *instance_monitor; - - if (!configured) - return TRUE; - - /* - Prepare instance to start Instance Monitor thread. - - NOTE: It's important to set these actions here in order to avoid - race conditions -- these actions must be done under acquired lock on - Instance. - */ - - crashed= FALSE; - monitoring_thread_active= TRUE; - - remove_pid(); - - /* Create and start the Instance Monitor thread. */ - - instance_monitor= new Instance_monitor(this); - - if (instance_monitor == NULL || instance_monitor->start(Thread::DETACHED)) - { - delete instance_monitor; - monitoring_thread_active= FALSE; - - log_error("Instance '%s': can not create instance monitor thread.", - (const char *) get_name()->str); - - return TRUE; - } - - ++restart_counter; - - /* The Instance Monitor thread will delete itself when it's finished. */ - - return FALSE; -} - - -/** - Stop mysqld. - - SYNOPSIS - stop_mysqld() - - DESCRIPTION - Try to stop mysqld gracefully. Otherwise kill it with SIGKILL. - - MT-NOTE: instance must be locked before calling the operation. - - RETURN - FALSE - ok - TRUE - could not stop the instance -*/ - -bool Instance::stop_mysqld() -{ - log_info("Instance '%s': stopping mysqld...", - (const char *) get_name()->str); - - kill_mysqld(SIGTERM); - - if (!wait_for_stop()) - { - log_info("Instance '%s': mysqld stopped gracefully.", - (const char *) get_name()->str); - return FALSE; - } - - log_info("Instance '%s': mysqld failed to stop gracefully within %d seconds.", - (const char *) get_name()->str, - (int) options.get_shutdown_delay()); - - log_info("Instance'%s': killing mysqld...", - (const char *) get_name()->str); - - kill_mysqld(SIGKILL); - - if (!wait_for_stop()) - { - log_info("Instance '%s': mysqld has been killed.", - (const char *) get_name()->str); - return FALSE; - } - - log_info("Instance '%s': can not kill mysqld within %d seconds.", - (const char *) get_name()->str, - (int) options.get_shutdown_delay()); - - return TRUE; -} - - -/** - Send signal to mysqld. - - SYNOPSIS - kill_mysqld() - - DESCRIPTION - Load pid from the pid file and send the given signal to that process. - If the signal is SIGKILL, remove the pid file after sending the signal. - - MT-NOTE: instance must be locked before calling the operation. - - TODO - This too low-level and OS-specific operation for public interface. - Also, it has some implicit behaviour for SIGKILL signal. Probably, we - should have the following public operations instead: - - start_mysqld() -- as is; - - stop_mysqld -- request mysqld to shutdown gracefully (send SIGTERM); - don't wait for complete shutdown; - - wait_for_stop() (or join_mysqld()) -- wait for mysqld to stop within - time interval; - - kill_mysqld() -- request to terminate mysqld; don't wait for - completion. - These operations should also be used in Guardian to manage instances. -*/ - -bool Instance::kill_mysqld(int signum) -{ - pid_t mysqld_pid= options.load_pid(); - - if (mysqld_pid == 0) - { - log_info("Instance '%s': no pid file to send a signal (%d).", - (const char *) get_name()->str, - (int) signum); - return TRUE; - } - - log_info("Instance '%s': sending %d to %d...", - (const char *) get_name()->str, - (int) signum, - (int) mysqld_pid); - - if (kill(mysqld_pid, signum)) - { - log_info("Instance '%s': kill() failed.", - (const char *) get_name()->str); - return TRUE; - } - - /* Kill suceeded */ - if (signum == SIGKILL) /* really killed instance with SIGKILL */ - { - log_error("Instance '%s': killed.", - (const char *) options.instance_name.str); - - /* After sucessful hard kill the pidfile need to be removed */ - options.unlink_pidfile(); - } - - return FALSE; -} - - -/** - Lock instance. -*/ - -void Instance::lock() -{ - pthread_mutex_lock(&LOCK_instance); -} - - -/** - Unlock instance. -*/ - -void Instance::unlock() -{ - pthread_mutex_unlock(&LOCK_instance); -} - - -/** - Return instance state name. - - SYNOPSIS - get_state_name() - - DESCRIPTION - The operation returns user-friendly state name. The operation can be - used both for guarded and non-guarded instances. - - MT-NOTE: instance must be locked before calling the operation. - - TODO: Replace with the static get_state_name(state_code) function. -*/ - -const char *Instance::get_state_name() -{ - if (!is_configured()) - return "misconfigured"; - - if (is_guarded()) - { - /* The instance is managed by Guardian: we can report precise state. */ - - return get_instance_state_name(get_state()); - } - - /* The instance is not managed by Guardian: we can report status only. */ - - return is_active() ? "online" : "offline"; -} - - -/** - Reset statistics. - - SYNOPSIS - reset_stat() - - DESCRIPTION - The operation resets statistics used for guarding the instance. - - MT-NOTE: instance must be locked before calling the operation. - - TODO: Make private. -*/ - -void Instance::reset_stat() -{ - restart_counter= 0; - crash_moment= 0; - last_checked= 0; -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Instance: implementation of private operations. -**************************************************************************/ - -/** - Remove pid file. -*/ - -void Instance::remove_pid() -{ - int mysqld_pid= options.load_pid(); - - if (mysqld_pid == 0) - return; - - if (options.unlink_pidfile()) - { - log_error("Instance '%s': can not unlink pid file.", - (const char *) options.instance_name.str); - } -} - - -/** - Wait for mysqld to stop within shutdown interval. -*/ - -bool Instance::wait_for_stop() -{ - int start_time= (int) time(NULL); - int finish_time= start_time + options.get_shutdown_delay(); - - log_info("Instance '%s': waiting for mysqld to stop " - "(timeout: %d seconds)...", - (const char *) get_name()->str, - (int) options.get_shutdown_delay()); - - while (true) - { - if (options.load_pid() == 0 && !is_mysqld_running()) - return FALSE; - - if (time(NULL) >= finish_time) - return TRUE; - - /* Sleep for 0.3 sec and check again. */ - - my_sleep(300000); - } -} - -/************************************************************************** - }}} -**************************************************************************/ diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h deleted file mode 100644 index aa9c923cba1..00000000000 --- a/server-tools/instance-manager/instance.h +++ /dev/null @@ -1,273 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include - -#include "instance_options.h" -#include "priv.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Instance_map; -class Thread_registry; - - -/** - Instance_name -- the class represents instance name -- a string of length - less than MAX_INSTANCE_NAME_SIZE. - - Generally, this is just a string with self-memory-management and should be - eliminated in the future. -*/ - -class Instance_name -{ -public: - Instance_name(const LEX_STRING *name); - -public: - inline const LEX_STRING *get_str() const - { - return &str; - } - - inline const char *get_c_str() const - { - return str.str; - } - - inline uint get_length() const - { - return str.length; - } - -private: - LEX_STRING str; - char str_buffer[MAX_INSTANCE_NAME_SIZE]; -}; - - -class Instance -{ -public: - /* States of an instance. */ - enum enum_instance_state - { - STOPPED, - NOT_STARTED, - STARTING, - STARTED, - JUST_CRASHED, - CRASHED, - CRASHED_AND_ABANDONED, - STOPPING - }; - -public: - /** - The constant defines name of the default mysqld-instance ("mysqld"). - */ - static const LEX_STRING DFLT_INSTANCE_NAME; - -public: - static bool is_name_valid(const LEX_STRING *name); - static bool is_mysqld_compatible_name(const LEX_STRING *name); - -public: - Instance(); - ~Instance(); - - bool init(const LEX_STRING *name_arg); - bool complete_initialization(); - -public: - bool is_active(); - - bool is_mysqld_running(); - - bool start_mysqld(); - bool stop_mysqld(); - bool kill_mysqld(int signo); - - void lock(); - void unlock(); - - const char *get_state_name(); - - void reset_stat(); - -public: - /** - The operation is intended to check if the instance is mysqld-compatible - or not. - */ - inline bool is_mysqld_compatible() const; - - /** - The operation is intended to check if the instance is configured properly - or not. Misconfigured instances are not managed. - */ - inline bool is_configured() const; - - /** - The operation returns TRUE if the instance is guarded and FALSE otherwise. - */ - inline bool is_guarded() const; - - /** - The operation returns name of the instance. - */ - inline const LEX_STRING *get_name() const; - - /** - The operation returns the current state of the instance. - - NOTE: At the moment should be used only for guarded instances. - */ - inline enum_instance_state get_state() const; - - /** - The operation changes the state of the instance. - - NOTE: At the moment should be used only for guarded instances. - TODO: Make private. - */ - inline void set_state(enum_instance_state new_state); - - /** - The operation returns crashed flag. - */ - inline bool is_crashed(); - -public: - /** - This attributes contains instance options. - - TODO: Make private. - */ - Instance_options options; - -private: - /** - monitoring_thread_active is TRUE if there is a thread that monitors the - corresponding mysqld-process. - */ - bool monitoring_thread_active; - - /** - crashed is TRUE when corresponding mysqld-process has been died after - start. - */ - bool crashed; - - /** - configured is TRUE when the instance is configured and FALSE otherwise. - Misconfigured instances are not managed. - */ - bool configured; - - /* - mysqld_compatible specifies whether the instance is mysqld-compatible - or not. Mysqld-compatible instances can contain only mysqld-specific - options. At the moment an instance is mysqld-compatible if its name is - "mysqld". - - The idea is that [mysqld] section should contain only mysqld-specific - options (no Instance Manager-specific options) to be readable by mysqld - program. - */ - bool mysqld_compatible; - - /* - Mutex protecting the instance. - */ - pthread_mutex_t LOCK_instance; - -private: - /* Guarded-instance attributes. */ - - /* state of an instance (i.e. STARTED, CRASHED, etc.) */ - enum_instance_state state; - -public: - /* the amount of attemts to restart instance (cleaned up at success) */ - int restart_counter; - - /* triggered at a crash */ - time_t crash_moment; - - /* General time field. Used to provide timeouts (at shutdown and restart) */ - time_t last_checked; - -private: - static const char *get_instance_state_name(enum_instance_state state); - -private: - void remove_pid(); - - bool wait_for_stop(); - -private: - friend class Instance_monitor; -}; - - -inline bool Instance::is_mysqld_compatible() const -{ - return mysqld_compatible; -} - - -inline bool Instance::is_configured() const -{ - return configured; -} - - -inline bool Instance::is_guarded() const -{ - return !options.nonguarded; -} - - -inline const LEX_STRING *Instance::get_name() const -{ - return &options.instance_name; -} - - -inline Instance::enum_instance_state Instance::get_state() const -{ - return state; -} - - -inline void Instance::set_state(enum_instance_state new_state) -{ - state= new_state; -} - - -inline bool Instance::is_crashed() -{ - return crashed; -} - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */ diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc deleted file mode 100644 index b137370b50a..00000000000 --- a/server-tools/instance-manager/instance_map.cc +++ /dev/null @@ -1,649 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "instance_map.h" - -#include -#include -#include - -#include "buffer.h" -#include "instance.h" -#include "log.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "options.h" -#include "priv.h" - -C_MODE_START - -/** - HASH-routines: get key of instance for storing in hash. -*/ - -static uchar* get_instance_key(const uchar* u, size_t* len, - my_bool __attribute__((unused)) t) -{ - const Instance *instance= (const Instance *) u; - *len= instance->options.instance_name.length; - return (uchar *) instance->options.instance_name.str; -} - -/** - HASH-routines: cleanup handler. -*/ - -static void delete_instance(void *u) -{ - Instance *instance= (Instance *) u; - delete instance; -} - -/** - The option handler to pass to the process_default_option_files function. - - SYNOPSIS - process_option() - ctx Handler context. Here it is an instance_map structure. - group_name The name of the group the option belongs to. - option The very option to be processed. It is already - prepared to be used in argv (has -- prefix) - - DESCRIPTION - - This handler checks whether a group is an instance group and adds - an option to the appropriate instance class. If this is the first - occurence of an instance name, we'll also create the instance - with such name and add it to the instance map. - - RETURN - 0 - ok - 1 - error occured -*/ - -static int process_option(void *ctx, const char *group, const char *option) -{ - Instance_map *map= (Instance_map*) ctx; - LEX_STRING group_str; - - group_str.str= (char *) group; - group_str.length= strlen(group); - - return map->process_one_option(&group_str, option); -} - -C_MODE_END - - -/** - Parse option string. - - SYNOPSIS - parse_option() - option_str [IN] option string (e.g. "--name=value") - option_name_buf [OUT] parsed name of the option. - Must be of (MAX_OPTION_LEN + 1) size. - option_value_buf [OUT] parsed value of the option. - Must be of (MAX_OPTION_LEN + 1) size. - - DESCRIPTION - This is an auxiliary function and should not be used externally. It is - intended to parse whole option string into option name and option value. -*/ - -static void parse_option(const char *option_str, - char *option_name_buf, - char *option_value_buf) -{ - const char *eq_pos; - const char *ptr= option_str; - - while (*ptr == '-') - ++ptr; - - strmake(option_name_buf, ptr, MAX_OPTION_LEN + 1); - - eq_pos= strchr(ptr, '='); - if (eq_pos) - { - option_name_buf[eq_pos - ptr]= 0; - strmake(option_value_buf, eq_pos + 1, MAX_OPTION_LEN + 1); - } - else - { - option_value_buf[0]= 0; - } -} - - -/** - Process one option from the configuration file. - - SYNOPSIS - Instance_map::process_one_option() - group group name - option option string (e.g. "--name=value") - - DESCRIPTION - This is an auxiliary function and should not be used externally. - It is used only by flush_instances(), which pass it to - process_option(). The caller ensures proper locking - of the instance map object. -*/ - /* - Process a given option and assign it to appropricate instance. This is - required for the option handler, passed to my_search_option_files(). - */ - -int Instance_map::process_one_option(const LEX_STRING *group, - const char *option) -{ - Instance *instance= NULL; - - if (!Instance::is_name_valid(group)) - { - /* - Current section name is not a valid instance name. - We should skip it w/o error. - */ - return 0; - } - - if (!(instance= (Instance *) hash_search(&hash, (uchar *) group->str, - group->length))) - { - if (!(instance= new Instance())) - return 1; - - if (instance->init(group) || add_instance(instance)) - { - delete instance; - return 1; - } - - if (instance->is_mysqld_compatible()) - log_info("Warning: instance name '%s' is mysqld-compatible.", - (const char *) group->str); - - log_info("mysqld instance '%s' has been added successfully.", - (const char *) group->str); - } - - if (option) - { - char option_name[MAX_OPTION_LEN + 1]; - char option_value[MAX_OPTION_LEN + 1]; - - parse_option(option, option_name, option_value); - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option_name)) - { - log_info("Warning: configuration of mysqld-compatible instance '%s' " - "contains IM-specific option '%s'. " - "This breaks backward compatibility for the configuration file.", - (const char *) group->str, - (const char *) option_name); - } - - Named_value option(option_name, option_value); - - if (instance->options.set_option(&option)) - return 1; /* the instance'll be deleted when we destroy the map */ - } - - return 0; -} - - -/** - Instance_map constructor. -*/ - -Instance_map::Instance_map() -{ - pthread_mutex_init(&LOCK_instance_map, 0); -} - - -/** - Initialize Instance_map internals. -*/ - -bool Instance_map::init() -{ - return hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0, - get_instance_key, delete_instance, 0); -} - - -/** - Reset Instance_map data. -*/ - -bool Instance_map::reset() -{ - hash_free(&hash); - return init(); -} - - -/** - Instance_map destructor. -*/ - -Instance_map::~Instance_map() -{ - lock(); - - /* - NOTE: it's necessary to synchronize on each instance before removal, - because Instance-monitoring thread can be still alive an hold the mutex - (because it is detached and we have no control over it). - */ - - while (true) - { - Iterator it(this); - Instance *instance= it.next(); - - if (!instance) - break; - - instance->lock(); - instance->unlock(); - - remove_instance(instance); - } - - hash_free(&hash); - unlock(); - - pthread_mutex_destroy(&LOCK_instance_map); -} - - -/** - Lock Instance_map. -*/ - -void Instance_map::lock() -{ - pthread_mutex_lock(&LOCK_instance_map); -} - - -/** - Unlock Instance_map. -*/ - -void Instance_map::unlock() -{ - pthread_mutex_unlock(&LOCK_instance_map); -} - - -/** - Check if there is an active instance or not. -*/ - -bool Instance_map::is_there_active_instance() -{ - Instance *instance; - Iterator iterator(this); - - while ((instance= iterator.next())) - { - bool active_instance_found; - - instance->lock(); - active_instance_found= instance->is_active(); - instance->unlock(); - - if (active_instance_found) - return TRUE; - } - - return FALSE; -} - - -/** - Add an instance into the internal hash. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -int Instance_map::add_instance(Instance *instance) -{ - return my_hash_insert(&hash, (uchar *) instance); -} - - -/** - Remove instance from the internal hash. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -int Instance_map::remove_instance(Instance *instance) -{ - return hash_delete(&hash, (uchar *) instance); -} - - -/** - Create a new instance and register it in the internal hash. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -int Instance_map::create_instance(const LEX_STRING *instance_name, - const Named_value_arr *options) -{ - Instance *instance= new Instance(); - - if (!instance) - { - log_error("Can not allocate instance (name: '%s').", - (const char *) instance_name->str); - return ER_OUT_OF_RESOURCES; - } - - if (instance->init(instance_name)) - { - log_error("Can not initialize instance (name: '%s').", - (const char *) instance_name->str); - delete instance; - return ER_OUT_OF_RESOURCES; - } - - for (int i= 0; options && i < options->get_size(); ++i) - { - Named_value option= options->get_element(i); - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option.get_name())) - { - log_error("IM-option (%s) can not be used " - "in configuration of mysqld-compatible instance (%s).", - (const char *) option.get_name(), - (const char *) instance_name->str); - delete instance; - return ER_INCOMPATIBLE_OPTION; - } - - instance->options.set_option(&option); - } - - if (instance->is_mysqld_compatible()) - log_info("Warning: instance name '%s' is mysqld-compatible.", - (const char *) instance_name->str); - - if (instance->complete_initialization()) - { - log_error("Can not complete initialization of instance (name: '%s').", - (const char *) instance_name->str); - delete instance; - return ER_OUT_OF_RESOURCES; - /* TODO: return more appropriate error code in this case. */ - } - - if (add_instance(instance)) - { - log_error("Can not register instance (name: '%s').", - (const char *) instance_name->str); - delete instance; - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/** - Return a pointer to the instance or NULL, if there is no such instance. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -Instance * Instance_map::find(const LEX_STRING *name) -{ - return (Instance *) hash_search(&hash, (uchar *) name->str, name->length); -} - - -/** - Init instances command line arguments after all options have been loaded. -*/ - -bool Instance_map::complete_initialization() -{ - bool mysqld_found; - - /* Complete initialization of all registered instances. */ - - for (uint i= 0; i < hash.records; ++i) - { - Instance *instance= (Instance *) hash_element(&hash, i); - - if (instance->complete_initialization()) - return TRUE; - } - - /* That's all if we are runnning in an ordinary mode. */ - - if (!Options::Main::mysqld_safe_compatible) - return FALSE; - - /* In mysqld-compatible mode we must ensure that there 'mysqld' instance. */ - - mysqld_found= find(&Instance::DFLT_INSTANCE_NAME) != NULL; - - if (mysqld_found) - return FALSE; - - if (create_instance(&Instance::DFLT_INSTANCE_NAME, NULL)) - { - log_error("Can not create default instance."); - return TRUE; - } - - switch (create_instance_in_file(&Instance::DFLT_INSTANCE_NAME, NULL)) - { - case 0: - case ER_CONF_FILE_DOES_NOT_EXIST: - /* - Continue if the instance has been added to the config file - successfully, or the config file just does not exist. - */ - break; - - default: - log_error("Can not add default instance to the config file."); - - Instance *instance= find(&Instance::DFLT_INSTANCE_NAME); - - if (instance) - remove_instance(instance); /* instance is deleted here. */ - - return TRUE; - } - - return FALSE; -} - - -/** - Load options from config files and create appropriate instance - structures. -*/ - -int Instance_map::load() -{ - int argc= 1; - /* this is a dummy variable for search_option_files() */ - uint args_used= 0; - const char *argv_options[3]; - char **argv= (char **) &argv_options; - char defaults_file_arg[FN_REFLEN]; - - /* the name of the program may be orbitrary here in fact */ - argv_options[0]= "mysqlmanager"; - - /* - If the option file was forced by the user when starting - the IM with --defaults-file=xxxx, make sure it is also - passed as --defaults-file, not only as Options::config_file. - This is important for option files given with relative path: - e.g. --defaults-file=my.cnf. - Otherwise my_search_option_files will treat "my.cnf" as a group - name and start looking for files named "my.cnf.cnf" in all - default dirs. Which is not what we want. - */ - if (Options::Main::is_forced_default_file) - { - snprintf(defaults_file_arg, FN_REFLEN, "--defaults-file=%s", - Options::Main::config_file); - - argv_options[1]= defaults_file_arg; - argv_options[2]= '\0'; - - argc= 2; - } - else - argv_options[1]= '\0'; - - /* - If the routine failed, we'll simply fallback to defaults in - complete_initialization(). - */ - if (my_search_option_files(Options::Main::config_file, &argc, - (char ***) &argv, &args_used, - process_option, (void*) this, - Options::default_directories)) - log_info("Falling back to compiled-in defaults."); - - return complete_initialization(); -} - - -/************************************************************************* - {{{ Instance_map::Iterator implementation. -*************************************************************************/ - -void Instance_map::Iterator::go_to_first() -{ - current_instance=0; -} - - -Instance *Instance_map::Iterator::next() -{ - if (current_instance < instance_map->hash.records) - return (Instance *) hash_element(&instance_map->hash, current_instance++); - - return NULL; -} - -/************************************************************************* - }}} -*************************************************************************/ - - -/** - Create a new configuration section for mysqld-instance in the config file. - - SYNOPSIS - create_instance_in_file() - instance_name mysqld-instance name - options options for the new mysqld-instance - - RETURN - 0 On success - ER_CONF_FILE_DOES_NOT_EXIST If config file does not exist - ER_ACCESS_OPTION_FILE If config file is not writable or some I/O - error ocurred during writing configuration -*/ - -int create_instance_in_file(const LEX_STRING *instance_name, - const Named_value_arr *options) -{ - File cnf_file; - - if (my_access(Options::Main::config_file, W_OK)) - { - log_error("Configuration file (%s) does not exist.", - (const char *) Options::Main::config_file); - return ER_CONF_FILE_DOES_NOT_EXIST; - } - - cnf_file= my_open(Options::Main::config_file, O_WRONLY | O_APPEND, MYF(0)); - - if (cnf_file <= 0) - { - log_error("Can not open configuration file (%s): %s.", - (const char *) Options::Main::config_file, - (const char *) strerror(errno)); - return ER_ACCESS_OPTION_FILE; - } - - if (my_write(cnf_file, (uchar*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)"[", 1, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)instance_name->str, instance_name->length, - MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)"]", 1, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP))) - { - log_error("Can not write to configuration file (%s): %s.", - (const char *) Options::Main::config_file, - (const char *) strerror(errno)); - my_close(cnf_file, MYF(0)); - return ER_ACCESS_OPTION_FILE; - } - - for (int i= 0; options && i < options->get_size(); ++i) - { - char option_str[MAX_OPTION_STR_LEN]; - char *ptr; - int option_str_len; - Named_value option= options->get_element(i); - - ptr= strxnmov(option_str, MAX_OPTION_LEN + 1, option.get_name(), NullS); - - if (option.get_value()[0]) - ptr= strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS); - - option_str_len= ptr - option_str; - - if (my_write(cnf_file, (uchar*)option_str, option_str_len, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP))) - { - log_error("Can not write to configuration file (%s): %s.", - (const char *) Options::Main::config_file, - (const char *) strerror(errno)); - my_close(cnf_file, MYF(0)); - return ER_ACCESS_OPTION_FILE; - } - } - - my_close(cnf_file, MYF(0)); - - return 0; -} diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h deleted file mode 100644 index af2f1868195..00000000000 --- a/server-tools/instance-manager/instance_map.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include -#include -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Guardian; -class Instance; -class Named_value_arr; -class Thread_registry; - -extern int load_all_groups(char ***groups, const char *filename); -extern void free_groups(char **groups); - -extern int create_instance_in_file(const LEX_STRING *instance_name, - const Named_value_arr *options); - - -/** - Instance_map - stores all existing instances -*/ - -class Instance_map -{ -public: - /** - Instance_map iterator - */ - - class Iterator - { - private: - uint current_instance; - Instance_map *instance_map; - public: - Iterator(Instance_map *instance_map_arg) : - current_instance(0), instance_map(instance_map_arg) - {} - - void go_to_first(); - Instance *next(); - }; - -public: - Instance *find(const LEX_STRING *name); - - bool is_there_active_instance(); - - void lock(); - void unlock(); - - bool init(); - bool reset(); - - int load(); - - int process_one_option(const LEX_STRING *group, const char *option); - - int add_instance(Instance *instance); - - int remove_instance(Instance *instance); - - int create_instance(const LEX_STRING *instance_name, - const Named_value_arr *options); - -public: - Instance_map(); - ~Instance_map(); - -private: - bool complete_initialization(); - -private: - enum { START_HASH_SIZE = 16 }; - pthread_mutex_t LOCK_instance_map; - HASH hash; - -private: - friend class Iterator; -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H */ diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc deleted file mode 100644 index 8b96d6f0f96..00000000000 --- a/server-tools/instance-manager/instance_options.cc +++ /dev/null @@ -1,753 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "instance_options.h" - -#include -#include -#include - -#include - -#include "buffer.h" -#include "instance.h" -#include "log.h" -#include "options.h" -#include "parse_output.h" -#include "priv.h" - - -/* Create "mysqld ..." command in the buffer */ - -static inline bool create_mysqld_command(Buffer *buf, - const LEX_STRING *mysqld_path, - const LEX_STRING *option) -{ - int position= 0; - - if (buf->get_size()) /* malloc succeeded */ - { -#ifdef __WIN__ - buf->append(position++, "\"", 1); -#endif - buf->append(position, mysqld_path->str, mysqld_path->length); - position+= mysqld_path->length; -#ifdef __WIN__ - buf->append(position++, "\"", 1); -#endif - /* here the '\0' character is copied from the option string */ - buf->append(position, option->str, option->length + 1); - - return buf->is_error() ? TRUE : FALSE; - } - return TRUE; -} - -static inline bool is_path_separator(char ch) -{ -#if defined(__WIN__) || defined(__NETWARE__) - /* On windows and netware more delimiters are possible */ - return ch == FN_LIBCHAR || ch == FN_DEVCHAR || ch == '/'; -#else - return ch == FN_LIBCHAR; /* Unixes */ -#endif -} - - -static char *find_last_path_separator(char *path, uint length) -{ - while (length) - { - if (is_path_separator(path[length])) - return path + length; - length--; - } - return NULL; /* No path separator found */ -} - - - -bool Instance_options::is_option_im_specific(const char *option_name) -{ - static const char *IM_SPECIFIC_OPTIONS[] = - { - "nonguarded", - "mysqld-path", - "shutdown-delay", - NULL - }; - - for (int i= 0; IM_SPECIFIC_OPTIONS[i]; ++i) - { - if (!strcmp(option_name, IM_SPECIFIC_OPTIONS[i])) - return TRUE; - } - - return FALSE; -} - - -Instance_options::Instance_options() - :mysqld_version(NULL), mysqld_socket(NULL), mysqld_datadir(NULL), - mysqld_pid_file(NULL), - nonguarded(NULL), - mysqld_port(NULL), - mysqld_port_val(0), - shutdown_delay(NULL), - shutdown_delay_val(0), - filled_default_options(0) -{ - mysqld_path.str= NULL; - mysqld_path.length= 0; - - mysqld_real_path.str= NULL; - mysqld_real_path.length= 0; - - memset(logs, 0, sizeof(logs)); -} - - -/* - Get compiled-in value of default_option - - SYNOPSIS - get_default_option() - result buffer to put found value - result_len buffer size - option_name the name of the option, prefixed with "--" - - DESCRIPTION - - Get compile-in value of requested option from server - - RETURN - 0 - ok - 1 - error occured -*/ - - -int Instance_options::get_default_option(char *result, size_t result_len, - const char *option_name) -{ - int rc= 1; - LEX_STRING verbose_option= - { C_STRING_WITH_LEN(" --no-defaults --verbose --help") }; - - /* reserve space for the path + option + final '\0' */ - Buffer cmd(mysqld_path.length + verbose_option.length + 1); - - if (create_mysqld_command(&cmd, &mysqld_path, &verbose_option)) - goto err; - - /* +2 eats first "--" from the option string (E.g. "--datadir") */ - rc= parse_output_and_get_value((char*) cmd.buffer, - option_name + 2, strlen(option_name + 2), - result, result_len, GET_VALUE); -err: - return rc; -} - - -/* - Fill mysqld_version option (used at initialization stage) - - SYNOPSIS - fill_instance_version() - - DESCRIPTION - - Get mysqld version string from "mysqld --version" output. - - RETURN - FALSE - ok - TRUE - error occured -*/ - -bool Instance_options::fill_instance_version() -{ - char result[MAX_VERSION_LENGTH]; - LEX_STRING version_option= - { C_STRING_WITH_LEN(" --no-defaults --version") }; - Buffer cmd(mysqld_path.length + version_option.length + 1); - - if (create_mysqld_command(&cmd, &mysqld_path, &version_option)) - { - log_error("Failed to get version of '%s': out of memory.", - (const char *) mysqld_path.str); - return TRUE; - } - - bzero(result, MAX_VERSION_LENGTH); - - if (parse_output_and_get_value((char*) cmd.buffer, STRING_WITH_LEN("Ver"), - result, MAX_VERSION_LENGTH, GET_LINE)) - { - log_error("Failed to get version of '%s': unexpected output.", - (const char *) mysqld_path.str); - return TRUE; - } - - DBUG_ASSERT(*result != '\0'); - - { - char *start; - - /* trim leading whitespaces */ - start= result; - while (my_isspace(default_charset_info, *start)) - ++start; - - mysqld_version= strdup_root(&alloc, start); - } - - return FALSE; -} - - -/* - Fill mysqld_real_path - - SYNOPSIS - fill_mysqld_real_path() - - DESCRIPTION - - Get the real path to mysqld from "mysqld --help" output. - Will print the realpath of mysqld between "Usage: " and "[OPTIONS]" - - This is needed if the mysqld_path variable is pointing at a - script(for example libtool) or a symlink. - - RETURN - FALSE - ok - TRUE - error occured -*/ - -bool Instance_options::fill_mysqld_real_path() -{ - char result[FN_REFLEN]; - LEX_STRING help_option= - { C_STRING_WITH_LEN(" --no-defaults --help") }; - Buffer cmd(mysqld_path.length + help_option.length); - - if (create_mysqld_command(&cmd, &mysqld_path, &help_option)) - { - log_error("Failed to get real path of '%s': out of memory.", - (const char *) mysqld_path.str); - return TRUE; - } - - bzero(result, FN_REFLEN); - - if (parse_output_and_get_value((char*) cmd.buffer, - STRING_WITH_LEN("Usage: "), - result, FN_REFLEN, - GET_LINE)) - { - log_error("Failed to get real path of '%s': unexpected output.", - (const char *) mysqld_path.str); - return TRUE; - } - - DBUG_ASSERT(*result != '\0'); - - { - char* options_str; - /* chop the path of at [OPTIONS] */ - if ((options_str= strstr(result, "[OPTIONS]"))) - *options_str= '\0'; - mysqld_real_path.str= strdup_root(&alloc, result); - mysqld_real_path.length= strlen(mysqld_real_path.str); - } - - return FALSE; -} - - -/* - Fill various log options - - SYNOPSIS - fill_log_options() - - DESCRIPTION - - Compute paths to enabled log files. If the path is not specified in the - instance explicitly (I.e. log=/home/user/mysql.log), we try to guess the - file name and placement. - - RETURN - FALSE - ok - TRUE - error occured -*/ - -bool Instance_options::fill_log_options() -{ - Buffer buff; - enum { MAX_LOG_OPTION_LENGTH= 256 }; - char datadir[MAX_LOG_OPTION_LENGTH]; - char hostname[MAX_LOG_OPTION_LENGTH]; - uint hostname_length; - struct log_files_st - { - const char *name; - uint length; - char **value; - const char *default_suffix; - } logs_st[]= - { - {"--log-error", 11, &(logs[IM_LOG_ERROR]), ".err"}, - {"--log", 5, &(logs[IM_LOG_GENERAL]), ".log"}, - {"--log-slow-queries", 18, &(logs[IM_LOG_SLOW]), "-slow.log"}, - {NULL, 0, NULL, NULL} - }; - struct log_files_st *log_files; - - /* compute hostname and datadir for the instance */ - if (mysqld_datadir == NULL) - { - if (get_default_option(datadir, MAX_LOG_OPTION_LENGTH, "--datadir")) - return TRUE; - } - else - { - /* below is safe, as --datadir always has a value */ - strmake(datadir, mysqld_datadir, MAX_LOG_OPTION_LENGTH - 1); - } - - if (gethostname(hostname,sizeof(hostname)-1) < 0) - strmov(hostname, "mysql"); - - hostname[MAX_LOG_OPTION_LENGTH - 1]= 0; /* Safety */ - hostname_length= strlen(hostname); - - - for (log_files= logs_st; log_files->name; log_files++) - { - for (int i=0; (argv[i] != 0); i++) - { - if (!strncmp(argv[i], log_files->name, log_files->length)) - { - /* - This is really log_files->name option if and only if it is followed - by '=', '\0' or space character. This way we can distinguish such - options as '--log' and '--log-bin'. This is checked in the following - two statements. - */ - if (argv[i][log_files->length] == '\0' || - my_isspace(default_charset_info, argv[i][log_files->length])) - { - char full_name[MAX_LOG_OPTION_LENGTH]; - - fn_format(full_name, hostname, datadir, "", - MY_UNPACK_FILENAME | MY_SAFE_PATH); - - - if ((MAX_LOG_OPTION_LENGTH - strlen(full_name)) <= - strlen(log_files->default_suffix)) - return TRUE; - - strmov(full_name + strlen(full_name), log_files->default_suffix); - - /* - If there were specified two identical logfiles options, - we would loose some memory in MEM_ROOT here. However - this situation is not typical. - */ - *(log_files->value)= strdup_root(&alloc, full_name); - } - - if (argv[i][log_files->length] == '=') - { - char full_name[MAX_LOG_OPTION_LENGTH]; - - fn_format(full_name, argv[i] +log_files->length + 1, - datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH); - - if (!(*(log_files->value)= strdup_root(&alloc, full_name))) - return TRUE; - } - } - } - } - - return FALSE; -} - - -/* - Get the full pid file name with path - - SYNOPSIS - get_pid_filaname() - result buffer to sotre the pidfile value - - IMPLEMENTATION - Get the data directory, then get the pid filename - (which is always set for an instance), then load the - full path with my_load_path(). It takes into account - whether it is already an absolute path or it should be - prefixed with the datadir and so on. - - RETURN - 0 - ok - 1 - error occured -*/ - -int Instance_options::get_pid_filename(char *result) -{ - char datadir[MAX_PATH_LEN]; - - if (mysqld_datadir == NULL) - { - /* we might get an error here if we have wrong path to the mysqld binary */ - if (get_default_option(datadir, sizeof(datadir), "--datadir")) - return 1; - } - else - strxnmov(datadir, MAX_PATH_LEN - 1, mysqld_datadir, "/", NullS); - - /* get the full path to the pidfile */ - my_load_path(result, mysqld_pid_file, datadir); - return 0; -} - - -int Instance_options::unlink_pidfile() -{ - return unlink(pid_file_with_path); -} - - -pid_t Instance_options::load_pid() -{ - FILE *pid_file_stream; - - /* get the pid */ - if ((pid_file_stream= my_fopen(pid_file_with_path, - O_RDONLY | O_BINARY, MYF(0))) != NULL) - { - pid_t pid; - - if (fscanf(pid_file_stream, "%i", &pid) != 1) - pid= -1; - my_fclose(pid_file_stream, MYF(0)); - return pid; - } - return 0; -} - - -bool Instance_options::complete_initialization() -{ - int arg_idx; - const char *tmp; - char *end; - char bin_name_firstchar; - - if (!mysqld_path.str) - { - /* - Need to copy the path to allocated memory, as convert_dirname() might - need to change it - */ - mysqld_path.str= strdup_root(&alloc, Options::Main::default_mysqld_path); - if (!mysqld_path.str) - return TRUE; - } - - mysqld_path.length= strlen(mysqld_path.str); - - /* - If we found path with no slashes (end == NULL), we should not call - convert_dirname() at all. As we have got relative path to the binary. - That is, user supposes that mysqld resides in the same dir as - mysqlmanager. - */ - if ((end= find_last_path_separator(mysqld_path.str, mysqld_path.length))) - { - bin_name_firstchar= end[1]; - - /* - Below we will conver the path to mysqld in the case, it was given - in a format of another OS (e.g. uses '/' instead of '\' etc). - Here we strip the path to get rid of the binary name ("mysqld"), - we do it by removing first letter of the binary name (e.g. 'm' - in "mysqld"). Later we put it back. - */ - end[1]= 0; - - /* convert dirname to the format of current OS */ - convert_dirname((char*)mysqld_path.str, mysqld_path.str, NullS); - - /* put back the first character of the binary name*/ - end[1]= bin_name_firstchar; - } - - if (mysqld_port) - mysqld_port_val= atoi(mysqld_port); - - if (shutdown_delay) - shutdown_delay_val= atoi(shutdown_delay); - - if (!(tmp= strdup_root(&alloc, "--no-defaults"))) - return TRUE; - - if (!mysqld_pid_file) - { - char pidfilename[MAX_PATH_LEN]; - char hostname[MAX_PATH_LEN]; - - /* - If we created only one istance [mysqld], because no config. files were - found, we would like to model mysqld pid file values. - */ - - if (!gethostname(hostname, sizeof(hostname) - 1)) - { - if (Instance::is_mysqld_compatible_name(&instance_name)) - strxnmov(pidfilename, MAX_PATH_LEN - 1, hostname, ".pid", NullS); - else - strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, "-", - hostname, ".pid", NullS); - } - else - { - if (Instance::is_mysqld_compatible_name(&instance_name)) - strxnmov(pidfilename, MAX_PATH_LEN - 1, "mysql", ".pid", NullS); - else - strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, ".pid", - NullS); - } - - Named_value option((char *) "pid-file", pidfilename); - - set_option(&option); - } - - if (get_pid_filename(pid_file_with_path)) - return TRUE; - - /* we need to reserve space for the final zero + possible default options */ - if (!(argv= (char**) - alloc_root(&alloc, (get_num_options() + 1 - + MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*)))) - return TRUE; - filled_default_options= 0; - - /* the path must be first in the argv */ - if (add_to_argv(mysqld_path.str)) - return TRUE; - - if (add_to_argv(tmp)) - return TRUE; - - arg_idx= filled_default_options; - for (int opt_idx= 0; opt_idx < get_num_options(); ++opt_idx) - { - char option_str[MAX_OPTION_STR_LEN]; - Named_value option= get_option(opt_idx); - - if (is_option_im_specific(option.get_name())) - continue; - - char *ptr= strxnmov(option_str, MAX_OPTION_LEN + 3, "--", option.get_name(), - NullS); - - if (option.get_value()[0]) - strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS); - - argv[arg_idx++]= strdup_root(&alloc, option_str); - } - - argv[arg_idx]= 0; - - if (fill_log_options() || fill_mysqld_real_path() || fill_instance_version()) - return TRUE; - - return FALSE; -} - - -bool Instance_options::set_option(Named_value *option) -{ - bool err_status; - int idx= find_option(option->get_name()); - char *option_name_str; - char *option_value_str; - - if (!(option_name_str= Named_value::alloc_str(option->get_name()))) - return TRUE; - - if (!(option_value_str= Named_value::alloc_str(option->get_value()))) - { - Named_value::free_str(&option_name_str); - return TRUE; - } - - Named_value option_copy(option_name_str, option_value_str); - - if (idx < 0) - err_status= options.add_element(&option_copy); - else - err_status= options.replace_element(idx, &option_copy); - - if (!err_status) - update_var(option_copy.get_name(), option_copy.get_value()); - else - option_copy.free(); - - return err_status; -} - - -void Instance_options::unset_option(const char *option_name) -{ - int idx= find_option(option_name); - - if (idx < 0) - return; /* the option has not been set. */ - - options.remove_element(idx); - - update_var(option_name, NULL); -} - - -void Instance_options::update_var(const char *option_name, - const char *option_value) -{ - struct options_st - { - const char *name; - uint name_len; - const char **var; - } options_def[]= - { - {"socket", 6, &mysqld_socket}, - {"port", 4, &mysqld_port}, - {"datadir", 7, &mysqld_datadir}, - {"pid-file", 8, &mysqld_pid_file}, - {"nonguarded", 10, &nonguarded}, - {"mysqld-path", 11, (const char **) &mysqld_path.str}, - {"shutdown-delay", 14, &shutdown_delay}, - {NULL, 0, NULL} - }; - - for (options_st *opt= options_def; opt->name; ++opt) - { - if (!strncmp(opt->name, option_name, opt->name_len)) - { - *(opt->var)= option_value; - break; - } - } -} - - -int Instance_options::find_option(const char *option_name) -{ - for (int i= 0; i < get_num_options(); i++) - { - if (!strcmp(get_option(i).get_name(), option_name)) - return i; - } - - return -1; -} - - -int Instance_options::add_to_argv(const char* option) -{ - DBUG_ASSERT(filled_default_options < MAX_NUMBER_OF_DEFAULT_OPTIONS); - - if (option) - argv[filled_default_options++]= (char*) option; - return 0; -} - - -/* function for debug purposes */ -void Instance_options::print_argv() -{ - int i; - - printf("printing out an instance %s argv:\n", - (const char *) instance_name.str); - - for (i=0; argv[i] != NULL; i++) - printf("argv: %s\n", argv[i]); -} - - -/* - We execute this function to initialize some options. - - RETURN - FALSE - ok - TRUE - memory allocation error -*/ - -bool Instance_options::init(const LEX_STRING *instance_name_arg) -{ - instance_name.length= instance_name_arg->length; - - init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0); - - if (options.init()) - return TRUE; - - if (!(instance_name.str= strmake_root(&alloc, instance_name_arg->str, - instance_name_arg->length))) - return TRUE; - - return FALSE; -} - - -Instance_options::~Instance_options() -{ - free_root(&alloc, MYF(0)); -} - - -uint Instance_options::get_shutdown_delay() const -{ - static const uint DEFAULT_SHUTDOWN_DELAY= 35; - - /* - NOTE: it is important to check shutdown_delay here, but use - shutdown_delay_val. The idea is that if the option is unset, - shutdown_delay will be NULL, but shutdown_delay_val will not be reset. - */ - - return shutdown_delay ? shutdown_delay_val : DEFAULT_SHUTDOWN_DELAY; -} - -int Instance_options::get_mysqld_port() const -{ - /* - NOTE: it is important to check mysqld_port here, but use mysqld_port_val. - The idea is that if the option is unset, mysqld_port will be NULL, but - mysqld_port_val will not be reset. - */ - - return mysqld_port ? mysqld_port_val : 0; -} - diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h deleted file mode 100644 index b0503815036..00000000000 --- a/server-tools/instance-manager/instance_options.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include - -#include "parse.h" -#include "portability.h" /* for pid_t on Win32 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - - -/* - This class contains options of an instance and methods to operate them. - - We do not provide this class with the means of synchronization as it is - supposed that options for instances are all loaded at once during the - instance_map initilization and we do not change them later. This way we - don't have to synchronize between threads. -*/ - -class Instance_options -{ -public: - /* The operation is used to check if the option is IM-specific or not. */ - static bool is_option_im_specific(const char *option_name); - -public: - Instance_options(); - ~Instance_options(); - - bool complete_initialization(); - - bool set_option(Named_value *option); - void unset_option(const char *option_name); - - inline int get_num_options() const; - inline Named_value get_option(int idx) const; - -public: - bool init(const LEX_STRING *instance_name_arg); - pid_t load_pid(); - int get_pid_filename(char *result); - int unlink_pidfile(); - void print_argv(); - - uint get_shutdown_delay() const; - int get_mysqld_port() const; - -public: - /* - We need this value to be greater or equal then FN_REFLEN found in - my_global.h to use my_load_path() - */ - enum { MAX_PATH_LEN= 512 }; - enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 }; - char pid_file_with_path[MAX_PATH_LEN]; - char **argv; - /* - Here we cache the version string, obtained from mysqld --version. - In the case when mysqld binary is not found we get NULL here. - */ - const char *mysqld_version; - /* We need the some options, so we store them as a separate pointers */ - const char *mysqld_socket; - const char *mysqld_datadir; - const char *mysqld_pid_file; - LEX_STRING instance_name; - LEX_STRING mysqld_path; - LEX_STRING mysqld_real_path; - const char *nonguarded; - /* log enums are defined in parse.h */ - char *logs[3]; - -private: - bool fill_log_options(); - bool fill_instance_version(); - bool fill_mysqld_real_path(); - int add_to_argv(const char *option); - int get_default_option(char *result, size_t result_len, - const char *option_name); - - void update_var(const char *option_name, const char *option_value); - int find_option(const char *option_name); - -private: - const char *mysqld_port; - uint mysqld_port_val; - const char *shutdown_delay; - uint shutdown_delay_val; - - uint filled_default_options; - MEM_ROOT alloc; - - Named_value_arr options; -}; - - -inline int Instance_options::get_num_options() const -{ - return options.get_size(); -} - - -inline Named_value Instance_options::get_option(int idx) const -{ - return options.get_element(idx); -} - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */ diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc deleted file mode 100644 index 4d8a33e7db1..00000000000 --- a/server-tools/instance-manager/listener.cc +++ /dev/null @@ -1,337 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "listener.h" - -#include -#include -#include - -#include -#ifndef __WIN__ -#include -#endif - -#include "log.h" -#include "mysql_connection.h" -#include "options.h" -#include "portability.h" -#include "priv.h" -#include "thread_registry.h" - - -static void set_non_blocking(int socket) -{ -#ifndef __WIN__ - int flags= fcntl(socket, F_GETFL, 0); - fcntl(socket, F_SETFL, flags | O_NONBLOCK); -#else - u_long arg= 1; - ioctlsocket(socket, FIONBIO, &arg); -#endif -} - - -static void set_no_inherit(int socket) -{ -#ifndef __WIN__ - int flags= fcntl(socket, F_GETFD, 0); - fcntl(socket, F_SETFD, flags | FD_CLOEXEC); -#endif -} - -const int Listener::LISTEN_BACK_LOG_SIZE= 5; /* standard backlog size */ - -Listener::Listener(Thread_registry *thread_registry_arg, - User_map *user_map_arg) - :thread_registry(thread_registry_arg), - user_map(user_map_arg), - total_connection_count(0), - num_sockets(0) -{ -} - - -/* - Listener::run() - listen all supported sockets and spawn a thread - to handle incoming connection. - Using 'die' in case of syscall failure is OK now - we don't hold any - resources and 'die' kills the signal thread automatically. To be rewritten - one day. - See also comments in mysqlmanager.cc to picture general Instance Manager - architecture. -*/ - -void Listener::run() -{ - int i, n= 0; - -#ifndef __WIN__ - struct sockaddr_un unix_socket_address; -#endif - - log_info("Listener: started."); - - thread_registry->register_thread(&thread_info); - - FD_ZERO(&read_fds); - - /* I. prepare 'listen' sockets */ - if (create_tcp_socket()) - goto err; - -#ifndef __WIN__ - if (create_unix_socket(unix_socket_address)) - goto err; -#endif - - /* II. Listen sockets and spawn childs */ - for (i= 0; i < num_sockets; i++) - n= max(n, sockets[i]); - n++; - - timeval tv; - while (!thread_registry->is_shutdown()) - { - fd_set read_fds_arg= read_fds; - /* - We should reintialize timer as on linux it is modified - to reflect amount of time not slept. - */ - tv.tv_sec= 0; - tv.tv_usec= 100000; - - /* - When using valgrind 2.0 this syscall doesn't get kicked off by a - signal during shutdown. This results in failing assert - (Thread_registry::~Thread_registry). Valgrind 2.2 works fine. - */ - int rc= select(n, &read_fds_arg, 0, 0, &tv); - - if (rc == 0 || rc == -1) - { - if (rc == -1 && errno != EINTR) - log_error("Listener: select() failed: %s.", - (const char *) strerror(errno)); - continue; - } - - - for (int socket_index= 0; socket_index < num_sockets; socket_index++) - { - /* Assuming that rc > 0 as we asked to wait forever */ - if (FD_ISSET(sockets[socket_index], &read_fds_arg)) - { - int client_fd= accept(sockets[socket_index], 0, 0); - /* accept may return -1 (failure or spurious wakeup) */ - if (client_fd >= 0) // connection established - { - set_no_inherit(client_fd); - - struct st_vio *vio= - vio_new(client_fd, - socket_index == 0 ? VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, - socket_index == 0 ? 1 : 0); - - if (vio != NULL) - handle_new_mysql_connection(vio); - else - { - shutdown(client_fd, SHUT_RDWR); - closesocket(client_fd); - } - } - } - } - } - - /* III. Release all resources and exit */ - - log_info("Listener: shutdown requested, exiting..."); - - for (i= 0; i < num_sockets; i++) - closesocket(sockets[i]); - -#ifndef __WIN__ - unlink(unix_socket_address.sun_path); -#endif - - thread_registry->unregister_thread(&thread_info); - - log_info("Listener: finished."); - return; - -err: - log_error("Listener: failed to initialize. Initiate shutdown..."); - - // we have to close the ip sockets in case of error - for (i= 0; i < num_sockets; i++) - closesocket(sockets[i]); - - thread_registry->set_error_status(); - thread_registry->unregister_thread(&thread_info); - thread_registry->request_shutdown(); - return; -} - -int Listener::create_tcp_socket() -{ - /* value to be set by setsockopt */ - int arg= 1; - - int ip_socket= socket(AF_INET, SOCK_STREAM, 0); - if (ip_socket == INVALID_SOCKET) - { - log_error("Listener: socket(AF_INET) failed: %s.", - (const char *) strerror(errno)); - return -1; - } - - struct sockaddr_in ip_socket_address; - bzero(&ip_socket_address, sizeof(ip_socket_address)); - - ulong im_bind_addr; - if (Options::Main::bind_address != 0) - { - im_bind_addr= (ulong) inet_addr(Options::Main::bind_address); - - if (im_bind_addr == (ulong) INADDR_NONE) - im_bind_addr= htonl(INADDR_ANY); - } - else - im_bind_addr= htonl(INADDR_ANY); - uint im_port= Options::Main::port_number; - - ip_socket_address.sin_family= AF_INET; - ip_socket_address.sin_addr.s_addr= im_bind_addr; - - - ip_socket_address.sin_port= (unsigned short) - htons((unsigned short) im_port); - - setsockopt(ip_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &arg, sizeof(arg)); - if (bind(ip_socket, (struct sockaddr *) &ip_socket_address, - sizeof(ip_socket_address))) - { - log_error("Listener: bind(ip socket) failed: %s.", - (const char *) strerror(errno)); - closesocket(ip_socket); - return -1; - } - - if (listen(ip_socket, LISTEN_BACK_LOG_SIZE)) - { - log_error("Listener: listen(ip socket) failed: %s.", - (const char *) strerror(errno)); - closesocket(ip_socket); - return -1; - } - - /* set the socket nonblocking */ - set_non_blocking(ip_socket); - - /* make sure that instances won't be listening our sockets */ - set_no_inherit(ip_socket); - - FD_SET(ip_socket, &read_fds); - sockets[num_sockets++]= ip_socket; - log_info("Listener: accepting connections on ip socket (port: %d)...", - (int) im_port); - return 0; -} - -#ifndef __WIN__ -int Listener:: -create_unix_socket(struct sockaddr_un &unix_socket_address) -{ - int unix_socket= socket(AF_UNIX, SOCK_STREAM, 0); - if (unix_socket == INVALID_SOCKET) - { - log_error("Listener: socket(AF_UNIX) failed: %s.", - (const char *) strerror(errno)); - return -1; - } - - bzero(&unix_socket_address, sizeof(unix_socket_address)); - - unix_socket_address.sun_family= AF_UNIX; - strmake(unix_socket_address.sun_path, Options::Main::socket_file_name, - sizeof(unix_socket_address.sun_path)); - unlink(unix_socket_address.sun_path); // in case we have stale socket file - - /* - POSIX specifies default permissions for a pathname created by bind - to be 0777. We need everybody to have access to the socket. - */ - mode_t old_mask= umask(0); - if (bind(unix_socket, (struct sockaddr *) &unix_socket_address, - sizeof(unix_socket_address))) - { - log_error("Listener: bind(unix socket) failed for '%s': %s.", - (const char *) unix_socket_address.sun_path, - (const char *) strerror(errno)); - close(unix_socket); - return -1; - } - - umask(old_mask); - - if (listen(unix_socket, LISTEN_BACK_LOG_SIZE)) - { - log_error("Listener: listen(unix socket) failed: %s.", - (const char *) strerror(errno)); - close(unix_socket); - return -1; - } - - /* set the socket nonblocking */ - set_non_blocking(unix_socket); - - /* make sure that instances won't be listening our sockets */ - set_no_inherit(unix_socket); - - log_info("Listener: accepting connections on unix socket '%s'...", - (const char *) unix_socket_address.sun_path); - sockets[num_sockets++]= unix_socket; - FD_SET(unix_socket, &read_fds); - return 0; -} -#endif - - -/* - Create new mysql connection. Created thread is responsible for deletion of - the Mysql_connection and Vio instances passed to it. - SYNOPSIS - handle_new_mysql_connection() -*/ - -void Listener::handle_new_mysql_connection(struct st_vio *vio) -{ - Mysql_connection *mysql_connection= - new Mysql_connection(thread_registry, user_map, - vio, ++total_connection_count); - if (mysql_connection == NULL || mysql_connection->start(Thread::DETACHED)) - { - log_error("Listener: can not start connection handler."); - delete mysql_connection; - vio_delete(vio); - } - /* The connection will delete itself when the thread is finished */ -} diff --git a/server-tools/instance-manager/listener.h b/server-tools/instance-manager/listener.h deleted file mode 100644 index 964fb361fb5..00000000000 --- a/server-tools/instance-manager/listener.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H - -#include "thread_registry.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Thread_registry; -class User_map; - -/** - Listener - a thread listening on sockets and spawning - connection threads. -*/ - -class Listener: public Thread -{ -public: - Listener(Thread_registry *thread_registry_arg, User_map *user_map_arg); - -protected: - virtual void run(); - -private: - static const int LISTEN_BACK_LOG_SIZE; - -private: - Thread_info thread_info; - Thread_registry *thread_registry; - User_map *user_map; - - ulong total_connection_count; - - int sockets[2]; - int num_sockets; - fd_set read_fds; - -private: - void handle_new_mysql_connection(struct st_vio *vio); - int create_tcp_socket(); - int create_unix_socket(struct sockaddr_un &unix_socket_address); -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H diff --git a/server-tools/instance-manager/log.cc b/server-tools/instance-manager/log.cc deleted file mode 100644 index 9f276523e49..00000000000 --- a/server-tools/instance-manager/log.cc +++ /dev/null @@ -1,196 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "log.h" - -#include -#include -#include - -#include - -#include "portability.h" /* for vsnprintf() on Windows. */ - -/* - TODO: - - add flexible header support - - rewrite all fprintf with fwrite - - think about using 'write' instead of fwrite/fprintf on POSIX systems -*/ - -/* - Format log entry and write it to the given stream. - SYNOPSIS - log() -*/ - -static void log(FILE *file,const char *level_tag, const char *format, - va_list args) -{ - /* - log() should be thread-safe; it implies that we either call fprintf() - once per log(), or use flockfile()/funlockfile(). But flockfile() is - POSIX, not ANSI C, so we try to vsnprintf the whole message to the - stack, and if stack buffer is not enough, to malloced string. When - message is formatted, it is fprintf()'ed to the file. - */ - - /* Format time like MYSQL_LOG does. */ - time_t now= time(0); - struct tm bd_time; // broken-down time - localtime_r(&now, &bd_time); - - char buff_date[128]; - sprintf(buff_date, "[%d/%lu] [%02d/%02d/%02d %02d:%02d:%02d] [%s] ", - (int) getpid(), - (unsigned long) pthread_self(), - (int) bd_time.tm_year % 100, - (int) bd_time.tm_mon + 1, - (int) bd_time.tm_mday, - (int) bd_time.tm_hour, - (int) bd_time.tm_min, - (int) bd_time.tm_sec, - (const char *) level_tag); - /* Format the message */ - char buff_stack[256]; - - int n= vsnprintf(buff_stack, sizeof(buff_stack), format, args); - /* - return value of vsnprintf can vary, according to various standards; - try to check all cases. - */ - char *buff_msg= buff_stack; - if (n < 0 || n == sizeof(buff_stack)) - { - int size= sizeof(buff_stack) * 2; - buff_msg= (char*) my_malloc(size, MYF(0)); - while (TRUE) - { - if (buff_msg == 0) - { - strmake(buff_stack, "log(): message is too big, my_malloc() failed", - sizeof(buff_stack) - 1); - buff_msg= buff_stack; - break; - } - n = vsnprintf(buff_msg, size, format, args); - if (n >= 0 && n < size) - break; - size*= 2; - /* realloc() does unnecessary memcpy */ - my_free(buff_msg, 0); - buff_msg= (char*) my_malloc(size, MYF(0)); - } - } - else if ((size_t) n > sizeof(buff_stack)) - { - buff_msg= (char*) my_malloc(n + 1, MYF(0)); -#ifdef DBUG - DBUG_ASSERT(n == vsnprintf(buff_msg, n + 1, format, args)); -#else - vsnprintf(buff_msg, n + 1, format, args); -#endif - } - fprintf(file, "%s%s\n", buff_date, buff_msg); - if (buff_msg != buff_stack) - my_free(buff_msg, 0); - - /* don't fflush() the file: buffering strategy is set in log_init() */ -} - -/************************************************************************** - Logging: implementation of public interface. -**************************************************************************/ - -/* - The function initializes logging sub-system. - - SYNOPSIS - log_init() -*/ - -void log_init() -{ - /* - stderr is unbuffered by default; there is no good of line buffering, - as all logging is performed linewise - so remove buffering from stdout - also - */ - setbuf(stdout, 0); -} - - -/* - The function is intended to log error messages. It precedes a message - with date, time and [ERROR] tag and print it to the stderr and stdout. - - We want to print it on stdout to be able to know in which context we got the - error - - SYNOPSIS - log_error() - format [IN] format string - ... [IN] arguments to format -*/ - -void log_error(const char *format, ...) -{ - va_list args; - va_start(args, format); - log(stdout, "ERROR", format, args); - fflush(stdout); - log(stderr, "ERROR", format, args); - fflush(stderr); - va_end(args); -} - - -/* - The function is intended to log information messages. It precedes - a message with date, time and [INFO] tag and print it to the stdout. - - SYNOPSIS - log_error() - format [IN] format string - ... [IN] arguments to format -*/ - -void log_info(const char *format, ...) -{ - va_list args; - va_start(args, format); - log(stdout, "INFO", format, args); - va_end(args); -} - -/* - The function prints information to the error log and eixt(1). - - SYNOPSIS - die() - format [IN] format string - ... [IN] arguments to format -*/ - -void die(const char *format, ...) -{ - va_list args; - fprintf(stderr,"%s: ", my_progname); - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - fprintf(stderr, "\n"); - exit(1); -} diff --git a/server-tools/instance-manager/log.h b/server-tools/instance-manager/log.h deleted file mode 100644 index e6c3b55c54c..00000000000 --- a/server-tools/instance-manager/log.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H - -/* - Logging facilities. - - Two logging streams are supported: error log and info log. - Additionally libdbug may be used for debug information output. - - ANSI C buffered I/O is used to perform logging. - - Logging is performed via stdout/stder, so one can reopen them to point to - ordinary files. To initialize logging environment log_init() must be called. - - Rationale: - - no MYSQL_LOG as it has BIN mode, and not easy to fetch from sql_class.h - - no constructors/desctructors to make logging available all the time -*/ - - -void log_init(); - - -void log_info(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format(printf, 1, 2))) -#endif - ; - - -void log_error(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))) -#endif - ; - - -void die(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))) -#endif - ; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc deleted file mode 100644 index 792461e41a9..00000000000 --- a/server-tools/instance-manager/manager.cc +++ /dev/null @@ -1,526 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "manager.h" - -#include -#include -#include -#include - -#include -#ifndef __WIN__ -#include -#endif - -#include "exit_codes.h" -#include "guardian.h" -#include "instance_map.h" -#include "listener.h" -#include "mysql_manager_error.h" -#include "mysqld_error.h" -#include "log.h" -#include "options.h" -#include "priv.h" -#include "thread_registry.h" -#include "user_map.h" - - -/********************************************************************** - {{{ Platform-specific implementation. -**********************************************************************/ - -#ifndef __WIN__ -void set_signals(sigset_t *mask) -{ - /* block signals */ - sigemptyset(mask); - sigaddset(mask, SIGINT); - sigaddset(mask, SIGTERM); - sigaddset(mask, SIGPIPE); - sigaddset(mask, SIGHUP); - signal(SIGPIPE, SIG_IGN); - - /* - We want this signal to be blocked in all theads but the signal - one. It is needed for the thr_alarm subsystem to work. - */ - sigaddset(mask,THR_SERVER_ALARM); - - /* all new threads will inherite this signal mask */ - pthread_sigmask(SIG_BLOCK, mask, NULL); - - /* - In our case the signal thread also implements functions of alarm thread. - Here we init alarm thread functionality. We suppose that we won't have - more then 10 alarms at the same time. - */ - init_thr_alarm(10); -} -#else - -bool have_signal; - -void onsignal(int signo) -{ - have_signal= TRUE; -} - -void set_signals(sigset_t *set) -{ - signal(SIGINT, onsignal); - signal(SIGTERM, onsignal); - have_signal= FALSE; -} - -int my_sigwait(const sigset_t *set, int *sig) -{ - while (!have_signal) - { - Sleep(100); - } - return 0; -} - -#endif - -/********************************************************************** - }}} -**********************************************************************/ - - -/********************************************************************** - {{{ Implementation of checking the actual thread model. -***********************************************************************/ - -namespace { /* no-indent */ - -class ThreadModelChecker: public Thread -{ -public: - ThreadModelChecker() - :main_pid(getpid()) - { } - -public: - inline bool is_linux_threads() const - { - return linux_threads; - } - -protected: - virtual void run() - { - linux_threads= main_pid != getpid(); - } - -private: - pid_t main_pid; - bool linux_threads; -}; - -bool check_if_linux_threads(bool *linux_threads) -{ - ThreadModelChecker checker; - - if (checker.start() || checker.join()) - return TRUE; - - *linux_threads= checker.is_linux_threads(); - - return FALSE; -} - -} - -/********************************************************************** - }}} -***********************************************************************/ - - -/********************************************************************** - Manager implementation -***********************************************************************/ - -Guardian *Manager::p_guardian; -Instance_map *Manager::p_instance_map; -Thread_registry *Manager::p_thread_registry; -User_map *Manager::p_user_map; - -#ifndef __WIN__ -bool Manager::linux_threads; -#endif // __WIN__ - - -/** - Request shutdown of guardian and threads registered in Thread_registry. - - SYNOPSIS - stop_all_threads() -*/ - -void Manager::stop_all_threads() -{ - /* - Let Guardian thread know that it should break it's processing cycle, - once it wakes up. - */ - p_guardian->request_shutdown(); - - /* Stop all threads. */ - p_thread_registry->deliver_shutdown(); - - /* Set error status in the thread registry. */ - p_thread_registry->set_error_status(); -} - - -/** - Initialize user map and load password file. - - SYNOPSIS - init_user_map() - - RETURN - FALSE on success - TRUE on failure -*/ - -bool Manager::init_user_map(User_map *user_map) -{ - int err_code; - const char *err_msg; - - if (user_map->init()) - { - log_error("Manager: can not initialize user list: out of memory."); - return TRUE; - } - - err_code= user_map->load(Options::Main::password_file_name, &err_msg); - - if (!err_code) - return FALSE; - - if (err_code == ERR_PASSWORD_FILE_DOES_NOT_EXIST && - Options::Main::mysqld_safe_compatible) - { - /* - The password file does not exist, but we are running in - mysqld_safe-compatible mode. Continue, but complain in log. - */ - - log_info("Warning: password file does not exist, " - "nobody will be able to connect to Instance Manager."); - - return FALSE; - } - - log_error("Manager: %s.", (const char *) err_msg); - - return TRUE; -} - - -/** - Main manager function. - - SYNOPSIS - main() - - DESCRIPTION - This is an entry point to the main instance manager process: - start listener thread, write pid file and enter into signal handling. - See also comments in mysqlmanager.cc to picture general Instance Manager - architecture. - - RETURNS - main() returns exit status (exit code). -*/ - -int Manager::main() -{ - bool shutdown_complete= FALSE; - pid_t manager_pid= getpid(); - - log_info("Manager: initializing..."); - -#ifndef __WIN__ - if (check_if_linux_threads(&linux_threads)) - { - log_error("Manager: can not determine thread model."); - return 1; - } - - log_info("Manager: detected threads model: %s.", - (const char *) (linux_threads ? "LINUX threads" : "POSIX threads")); -#endif // __WIN__ - - /* - All objects created in the Manager object live as long as thread_registry - lives, and thread_registry is alive until there are working threads. - - There are two main purposes of the Thread Registry: - 1. Interrupt blocking I/O and signal condition variables in case of - shutdown; - 2. Wait for detached threads before shutting down the main thread. - - NOTE: - 1. Handling shutdown can be done in more elegant manner by introducing - Event (or Condition) object with support of logical operations. - 2. Using Thread Registry to wait for detached threads is definitely not - the best way, because when Thread Registry unregisters an thread, the - thread is still alive. Accurate way to wait for threads to stop is - not using detached threads and join all threads before shutdown. - */ - - Thread_registry thread_registry; - User_map user_map; - Instance_map instance_map; - Guardian guardian(&thread_registry, &instance_map); - - Listener listener(&thread_registry, &user_map); - - p_instance_map= &instance_map; - p_guardian= &guardian; - p_thread_registry= &thread_registry; - p_user_map= &user_map; - - /* Initialize instance map. */ - - if (instance_map.init()) - { - log_error("Manager: can not initialize instance list: out of memory."); - return 1; - } - - /* Initialize user db. */ - - if (init_user_map(&user_map)) - return 1; /* logging has been already done. */ - - /* Write Instance Manager pid file. */ - - if (create_pid_file(Options::Main::pid_file_name, manager_pid)) - return 1; /* necessary logging has been already done. */ - - log_info("Manager: pid file (%s) created.", - (const char *) Options::Main::pid_file_name); - - /* - Initialize signals and alarm-infrastructure. - - NOTE: To work nicely with LinuxThreads, the signal thread is the first - thread in the process. - - NOTE: After init_thr_alarm() call it's possible to call thr_alarm() - (from different threads), that results in sending ALARM signal to the - alarm thread (which can be the main thread). That signal can interrupt - blocking calls. In other words, a blocking call can be interrupted in - the main thread after init_thr_alarm(). - */ - - sigset_t mask; - set_signals(&mask); - - /* - Create the guardian thread. The newly started thread will block until - we actually load instances. - - NOTE: Guardian should be shutdown first. Only then all other threads - can be stopped. This should be done in this order because the guardian - is responsible for shutting down all the guarded instances, and this - is a long operation. - - NOTE: Guardian uses thr_alarm() when detects the current state of an - instance (is_running()), but this does not interfere with - flush_instances() call later in the code, because until - flush_instances() completes in the main thread, Guardian thread is not - permitted to process instances. And before flush_instances() has - completed, there are no instances to guard. - */ - - if (guardian.start(Thread::DETACHED)) - { - log_error("Manager: can not start Guardian thread."); - goto err; - } - - /* Load instances. */ - - if (Manager::flush_instances()) - { - log_error("Manager: can not init instances repository."); - stop_all_threads(); - goto err; - } - - /* Initialize the Listener. */ - - if (listener.start(Thread::DETACHED)) - { - log_error("Manager: can not start Listener thread."); - stop_all_threads(); - goto err; - } - - /* - After the list of guarded instances have been initialized, - Guardian should start them. - */ - - guardian.ping(); - - /* Main loop. */ - - log_info("Manager: started."); - - while (!shutdown_complete) - { - int signo; - int status= 0; - - if ((status= my_sigwait(&mask, &signo)) != 0) - { - log_error("Manager: sigwait() failed"); - stop_all_threads(); - goto err; - } - - /* - The general idea in this loop is the following: - - we are waiting for SIGINT, SIGTERM -- signals that mean we should - shutdown; - - as shutdown signal is caught, we stop Guardian thread (by calling - Guardian::request_shutdown()); - - as Guardian is stopped, it sends SIGTERM to this thread - (by calling Thread_registry::request_shutdown()), so that the - my_sigwait() above returns; - - as we catch the second SIGTERM, we send signals to all threads - registered in Thread_registry (by calling - Thread_registry::deliver_shutdown()) and waiting for threads to stop; - */ - -#ifndef __WIN__ -/* - On some Darwin kernels SIGHUP is delivered along with most - signals. This is why we skip it's processing on these - platforms. For more details and test program see - Bug #14164 IM tests fail on MacOS X (powermacg5) -*/ -#ifdef IGNORE_SIGHUP_SIGQUIT - if (SIGHUP == signo) - continue; -#endif - if (THR_SERVER_ALARM == signo) - process_alarm(signo); - else -#endif - { - log_info("Manager: got shutdown signal."); - - if (!guardian.is_stopped()) - { - guardian.request_shutdown(); - } - else - { - thread_registry.deliver_shutdown(); - shutdown_complete= TRUE; - } - } - } - - log_info("Manager: finished."); - -err: - /* delete the pid file */ - my_delete(Options::Main::pid_file_name, MYF(0)); - -#ifndef __WIN__ - /* free alarm structures */ - end_thr_alarm(1); -#endif - - return thread_registry.get_error_status() ? 1 : 0; -} - - -/** - Re-read instance configuration file. - - SYNOPSIS - flush_instances() - - DESCRIPTION - This function will: - - clear the current list of instances. This removes both - running and stopped instances. - - load a new instance configuration from the file. - - pass on the new map to the guardian thread: it will start - all instances that are marked `guarded' and not yet started. - - Note, as the check whether an instance is started is currently - very simple (returns TRUE if there is a MySQL server running - at the given port), this function has some peculiar - side-effects: - * if the port number of a running instance was changed, the - old instance is forgotten, even if it was running. The new - instance will be started at the new port. - * if the configuration was changed in a way that two - instances swapped their port numbers, the guardian thread - will not notice that and simply report that both instances - are configured successfully and running. - - In order to avoid such side effects one should never call - FLUSH INSTANCES without prior stop of all running instances. - - RETURN - 0 On success - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_THERE_IS_ACTIVE_INSTACE If there is an active instance -*/ - -int Manager::flush_instances() -{ - p_instance_map->lock(); - - if (p_instance_map->is_there_active_instance()) - { - p_instance_map->unlock(); - return ER_THERE_IS_ACTIVE_INSTACE; - } - - if (p_instance_map->reset()) - { - p_instance_map->unlock(); - return ER_OUT_OF_RESOURCES; - } - - if (p_instance_map->load()) - { - p_instance_map->unlock(); - - /* Don't init guardian if we failed to load instances. */ - return ER_OUT_OF_RESOURCES; - } - - get_guardian()->init(); - get_guardian()->ping(); - - p_instance_map->unlock(); - - return 0; -} diff --git a/server-tools/instance-manager/manager.h b/server-tools/instance-manager/manager.h deleted file mode 100644 index e6956884603..00000000000 --- a/server-tools/instance-manager/manager.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -#include - -class Guardian; -class Instance_map; -class Thread_registry; -class User_map; - -class Manager -{ -public: - static int main(); - - static int flush_instances(); - -public: - /** - These methods return a non-NULL value only for the duration - of main(). - */ - static Instance_map *get_instance_map() { return p_instance_map; } - static Guardian *get_guardian() { return p_guardian; } - static Thread_registry *get_thread_registry() { return p_thread_registry; } - static User_map *get_user_map() { return p_user_map; } - -public: -#ifndef __WIN__ - static bool is_linux_threads() { return linux_threads; } -#endif // __WIN__ - -private: - static void stop_all_threads(); - static bool init_user_map(User_map *user_map); - -private: - static Guardian *p_guardian; - static Instance_map *p_instance_map; - static Thread_registry *p_thread_registry; - static User_map *p_user_map; - -#ifndef __WIN__ - /* - This flag is set if Instance Manager is running on the system using - LinuxThreads. - */ - static bool linux_threads; -#endif // __WIN__ -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H diff --git a/server-tools/instance-manager/messages.cc b/server-tools/instance-manager/messages.cc deleted file mode 100644 index 201ebfd62fc..00000000000 --- a/server-tools/instance-manager/messages.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "messages.h" - -#include -#include - -#include "mysqld_error.h" -#include "mysql_manager_error.h" - - -static const char *mysqld_error_message(unsigned sql_errno) -{ - switch (sql_errno) { - case ER_HANDSHAKE_ERROR: - return "Bad handshake"; - case ER_OUT_OF_RESOURCES: - return "Out of memory; Check if mysqld or some other process" - " uses all available memory. If not you may have to use" - " 'ulimit' to allow mysqld to use more memory or you can" - " add more swap space"; - case ER_ACCESS_DENIED_ERROR: - return "Access denied. Bad username/password pair"; - case ER_NOT_SUPPORTED_AUTH_MODE: - return "Client does not support authentication protocol requested by" - " server; consider upgrading MySQL client"; - case ER_UNKNOWN_COM_ERROR: - return "Unknown command"; - case ER_SYNTAX_ERROR: - return "You have an error in your command syntax. Check the manual that" - " corresponds to your MySQL Instance Manager version for the right" - " syntax to use"; - case ER_BAD_INSTANCE_NAME: - return "Unknown instance name"; - case ER_INSTANCE_IS_NOT_STARTED: - return "Cannot stop instance. Perhaps the instance is not started, or was" - " started manually, so IM cannot find the pidfile."; - case ER_INSTANCE_ALREADY_STARTED: - return "The instance is already started"; - case ER_CANNOT_START_INSTANCE: - return "Cannot start instance. Possible reasons are wrong instance options" - " or resources shortage"; - case ER_OFFSET_ERROR: - return "Cannot read negative number of bytes"; - case ER_STOP_INSTANCE: - return "Cannot stop instance"; - case ER_READ_FILE: - return "Cannot read requested part of the logfile"; - case ER_NO_SUCH_LOG: - return "The instance has no such log enabled"; - case ER_OPEN_LOGFILE: - return "Cannot open log file"; - case ER_GUESS_LOGFILE: - return "Cannot guess the log filename. Try specifying full log name" - " in the instance options"; - case ER_ACCESS_OPTION_FILE: - return "Cannot open the option file to edit. Check permissions"; - case ER_DROP_ACTIVE_INSTANCE: - return "Cannot drop an active instance. You should stop it first"; - case ER_CREATE_EXISTING_INSTANCE: - return "Instance already exists"; - case ER_INSTANCE_MISCONFIGURED: - return "Instance is misconfigured. Cannot start it"; - case ER_MALFORMED_INSTANCE_NAME: - return "Malformed instance name."; - case ER_INSTANCE_IS_ACTIVE: - return "The instance is active. Stop the instance first"; - case ER_THERE_IS_ACTIVE_INSTACE: - return "At least one instance is active. Stop all instances first"; - case ER_INCOMPATIBLE_OPTION: - return "Instance Manager-specific options are prohibited from being used " - "in the configuration of mysqld-compatible instances"; - case ER_CONF_FILE_DOES_NOT_EXIST: - return "Configuration file does not exist"; - default: - DBUG_ASSERT(0); - return 0; - } -} - - -const char *message(unsigned sql_errno) -{ - return mysqld_error_message(sql_errno); -} - - -const char *errno_to_sqlstate(unsigned sql_errno) -{ - return mysql_errno_to_sqlstate(sql_errno); -} diff --git a/server-tools/instance-manager/messages.h b/server-tools/instance-manager/messages.h deleted file mode 100644 index 5d9383093bc..00000000000 --- a/server-tools/instance-manager/messages.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H - -const char *message(unsigned sql_errno); - -const char *errno_to_sqlstate(unsigned sql_errno); - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc deleted file mode 100644 index 12ea0a3ea5a..00000000000 --- a/server-tools/instance-manager/mysql_connection.cc +++ /dev/null @@ -1,376 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "mysql_connection.h" - -#include -#include -#include -#include -#include -#include - -#include "command.h" -#include "log.h" -#include "messages.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "parse.h" -#include "priv.h" -#include "protocol.h" -#include "thread_registry.h" -#include "user_map.h" - - -Mysql_connection::Mysql_connection(Thread_registry *thread_registry_arg, - User_map *user_map_arg, - struct st_vio *vio_arg, ulong - connection_id_arg) - :vio(vio_arg), - connection_id(connection_id_arg), - thread_registry(thread_registry_arg), - user_map(user_map_arg) -{ -} - - -/* - NET subsystem requieres its user to provide my_net_local_init extern - C function (exactly as declared below). my_net_local_init is called by - my_net_init and is supposed to set NET controlling variables. - See also priv.h for variables description. -*/ - -C_MODE_START - -void my_net_local_init(NET *net) -{ - net->max_packet= net_buffer_length; - my_net_set_read_timeout(net, (uint)net_read_timeout); - my_net_set_write_timeout(net, (uint)net_write_timeout); - net->retry_count= net_retry_count; - net->max_packet_size= max_allowed_packet; -} - -C_MODE_END - -/* - Unused stub hook required for linking the client API. -*/ - -C_MODE_START - -void slave_io_thread_detach_vio() -{ -} - -C_MODE_END - - -/* - Every resource, which we can fail to acquire, is allocated in init(). - This function is complementary to cleanup(). -*/ - -bool Mysql_connection::init() -{ - /* Allocate buffers for network I/O */ - if (my_net_init(&net, vio)) - return TRUE; - - net.return_status= &status; - - /* Initialize random number generator */ - { - ulong seed1= (ulong) &rand_st + rand(); - ulong seed2= (ulong) rand() + (ulong) time(0); - randominit(&rand_st, seed1, seed2); - } - - /* Fill scramble - server's random message used for handshake */ - create_random_string(scramble, SCRAMBLE_LENGTH, &rand_st); - - /* We don't support transactions, every query is atomic */ - status= SERVER_STATUS_AUTOCOMMIT; - - thread_registry->register_thread(&thread_info); - - return FALSE; -} - - -void Mysql_connection::cleanup() -{ - net_end(&net); - thread_registry->unregister_thread(&thread_info); -} - - -Mysql_connection::~Mysql_connection() -{ - /* vio_delete closes the socket if necessary */ - vio_delete(vio); -} - - -void Mysql_connection::main() -{ - log_info("Connection %lu: accepted.", (unsigned long) connection_id); - - if (check_connection()) - { - log_info("Connection %lu: failed to authorize the user.", - (unsigned long) connection_id); - - return; - } - - log_info("Connection %lu: the user was authorized successfully.", - (unsigned long) connection_id); - - vio_keepalive(vio, TRUE); - - while (!net.error && net.vio && !thread_registry->is_shutdown()) - { - if (do_command()) - break; - } -} - - -int Mysql_connection::check_connection() -{ - ulong pkt_len=0; // to hold client reply length - - /* buffer for the first packet */ /* packet contains: */ - uchar buff[MAX_VERSION_LENGTH + 1 + // server version, 0-ended - 4 + // connection id - SCRAMBLE_LENGTH + 2 + // scramble (in 2 pieces) - 18]; // server variables: flags, - // charset number, status, - uchar *pos= buff; - ulong server_flags; - - memcpy(pos, mysqlmanager_version.str, mysqlmanager_version.length + 1); - pos+= mysqlmanager_version.length + 1; - - int4store((uchar*) pos, connection_id); - pos+= 4; - - /* - Old clients does not understand long scrambles, but can ignore packet - tail: that's why first part of the scramble is placed here, and second - part at the end of packet (even though we don't support old clients, - we must follow standard packet format.) - */ - memcpy(pos, scramble, SCRAMBLE_LENGTH_323); - pos+= SCRAMBLE_LENGTH_323; - *pos++= '\0'; - - server_flags= CLIENT_LONG_FLAG | CLIENT_PROTOCOL_41 | - CLIENT_SECURE_CONNECTION; - - /* - 18-bytes long section for various flags/variables - - Every flag occupies a bit in first half of ulong; int2store will - gracefully pick up all flags. - */ - int2store(pos, server_flags); - pos+= 2; - *pos++= (char) default_charset_info->number; // global mysys variable - int2store(pos, status); // connection status - pos+= 2; - bzero(pos, 13); // not used now - pos+= 13; - - /* second part of the scramble, null-terminated */ - memcpy(pos, scramble + SCRAMBLE_LENGTH_323, - SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1); - pos+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1; - - /* write connection message and read reply */ - enum { MIN_HANDSHAKE_SIZE= 2 }; - if (net_write_command(&net, protocol_version, (uchar*) "", 0, - buff, pos - buff) || - (pkt_len= my_net_read(&net)) == packet_error || - pkt_len < MIN_HANDSHAKE_SIZE) - { - net_send_error(&net, ER_HANDSHAKE_ERROR); - return 1; - } - - client_capabilities= uint2korr(net.read_pos); - if (!(client_capabilities & CLIENT_PROTOCOL_41)) - { - net_send_error_323(&net, ER_NOT_SUPPORTED_AUTH_MODE); - return 1; - } - client_capabilities|= ((ulong) uint2korr(net.read_pos + 2)) << 16; - - pos= net.read_pos + 32; - - /* At least one byte for username and one byte for password */ - if (pos >= net.read_pos + pkt_len + 2) - { - /*TODO add user and password handling in error messages*/ - net_send_error(&net, ER_HANDSHAKE_ERROR); - return 1; - } - - const char *user= (char*) pos; - const char *password= strend(user)+1; - ulong password_len= *password++; - LEX_STRING user_name= { (char *) user, password - user - 2 }; - - if (password_len != SCRAMBLE_LENGTH) - { - net_send_error(&net, ER_ACCESS_DENIED_ERROR); - return 1; - } - if (user_map->authenticate(&user_name, password, scramble)) - { - net_send_error(&net, ER_ACCESS_DENIED_ERROR); - return 1; - } - net_send_ok(&net, connection_id, NULL); - return 0; -} - - -int Mysql_connection::do_command() -{ - char *packet; - ulong packet_length; - - /* We start to count packets from 0 for each new command */ - net.pkt_nr= 0; - - if ((packet_length=my_net_read(&net)) == packet_error) - { - /* Check if we can continue without closing the connection */ - if (net.error != 3) // what is 3 - find out - return 1; - if (thread_registry->is_shutdown()) - return 1; - net_send_error(&net, net.last_errno); - net.error= 0; - return 0; - } - else - { - if (thread_registry->is_shutdown()) - return 1; - packet= (char*) net.read_pos; - enum enum_server_command command= (enum enum_server_command) - (uchar) *packet; - log_info("Connection %lu: received packet (length: %lu; command: %d).", - (unsigned long) connection_id, - (unsigned long) packet_length, - (int) command); - - return dispatch_command(command, packet + 1); - } -} - -int Mysql_connection::dispatch_command(enum enum_server_command command, - const char *packet) -{ - switch (command) { - case COM_QUIT: // client exit - log_info("Connection %lu: received QUIT command.", - (unsigned long) connection_id); - return 1; - - case COM_PING: - log_info("Connection %lu: received PING command.", - (unsigned long) connection_id); - net_send_ok(&net, connection_id, NULL); - return 0; - - case COM_QUERY: - { - log_info("Connection %lu: received QUERY command: '%s'.", - (unsigned long) connection_id, - (const char *) packet); - - if (Command *com= parse_command(packet)) - { - int res= 0; - - log_info("Connection %lu: query parsed successfully.", - (unsigned long) connection_id); - - res= com->execute(&net, connection_id); - delete com; - if (!res) - { - log_info("Connection %lu: query executed successfully", - (unsigned long) connection_id); - } - else - { - log_info("Connection %lu: can not execute query (error: %d).", - (unsigned long) connection_id, - (int) res); - - net_send_error(&net, res); - } - } - else - { - log_error("Connection %lu: can not parse query: out ot resources.", - (unsigned long) connection_id); - - net_send_error(&net,ER_OUT_OF_RESOURCES); - } - - return 0; - } - - default: - log_info("Connection %lu: received unsupported command (%d).", - (unsigned long) connection_id, - (int) command); - - net_send_error(&net, ER_UNKNOWN_COM_ERROR); - return 0; - } - - return 0; /* Just to make compiler happy. */ -} - - -void Mysql_connection::run() -{ - if (init()) - log_error("Connection %lu: can not init handler.", - (unsigned long) connection_id); - else - { - main(); - cleanup(); - } - - delete this; -} - -/* - vim: fdm=marker -*/ diff --git a/server-tools/instance-manager/mysql_connection.h b/server-tools/instance-manager/mysql_connection.h deleted file mode 100644 index 56bbf76e146..00000000000 --- a/server-tools/instance-manager/mysql_connection.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H - -#include "thread_registry.h" -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -struct st_vio; -class User_map; - -/* - MySQL connection - handle one connection with mysql command line client - See also comments in mysqlmanager.cc to picture general Instance Manager - architecture. - We use conventional technique to work with classes without exceptions: - class acquires all vital resource in init(); Thus if init() succeed, - a user must call cleanup(). All other methods are valid only between - init() and cleanup(). -*/ - -class Mysql_connection: public Thread -{ -public: - Mysql_connection(Thread_registry *thread_registry_arg, - User_map *user_map_arg, - struct st_vio *vio_arg, - ulong connection_id_arg); - virtual ~Mysql_connection(); - -protected: - virtual void run(); - -private: - struct st_vio *vio; - ulong connection_id; - Thread_info thread_info; - Thread_registry *thread_registry; - User_map *user_map; - NET net; - struct rand_struct rand_st; - char scramble[SCRAMBLE_LENGTH + 1]; - uint status; - ulong client_capabilities; -private: - /* The main loop implementation triad */ - bool init(); - void main(); - void cleanup(); - - /* Names are conventionally the same as in mysqld */ - int check_connection(); - int do_command(); - int dispatch_command(enum enum_server_command command, const char *text); -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H diff --git a/server-tools/instance-manager/mysql_manager_error.h b/server-tools/instance-manager/mysql_manager_error.h deleted file mode 100644 index e50e5d24f6d..00000000000 --- a/server-tools/instance-manager/mysql_manager_error.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Definefile for instance manager error messagenumbers */ - -#define ER_BAD_INSTANCE_NAME 3000 -#define ER_INSTANCE_IS_NOT_STARTED 3001 -#define ER_INSTANCE_ALREADY_STARTED 3002 -#define ER_CANNOT_START_INSTANCE 3003 -#define ER_STOP_INSTANCE 3004 -#define ER_NO_SUCH_LOG 3005 -#define ER_OPEN_LOGFILE 3006 -#define ER_GUESS_LOGFILE 3007 -#define ER_ACCESS_OPTION_FILE 3008 -#define ER_OFFSET_ERROR 3009 -#define ER_READ_FILE 3010 -#define ER_DROP_ACTIVE_INSTANCE 3011 -#define ER_CREATE_EXISTING_INSTANCE 3012 -#define ER_INSTANCE_MISCONFIGURED 3013 -#define ER_MALFORMED_INSTANCE_NAME 3014 -#define ER_INSTANCE_IS_ACTIVE 3015 -#define ER_THERE_IS_ACTIVE_INSTACE 3016 -#define ER_INCOMPATIBLE_OPTION 3017 -#define ER_CONF_FILE_DOES_NOT_EXIST 3018 - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */ diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc deleted file mode 100644 index 276d1ca3b49..00000000000 --- a/server-tools/instance-manager/mysqlmanager.cc +++ /dev/null @@ -1,232 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include -#include - -#include - -#ifndef __WIN__ -#include -#include -#endif - -#include "angel.h" -#include "log.h" -#include "manager.h" -#include "options.h" -#include "user_management_commands.h" - -#ifdef __WIN__ -#include "IMService.h" -#endif - - -/* - Instance Manager consists of two processes: the angel process (IM-angel), - and the manager process (IM-main). Responsibilities of IM-angel is to - monitor IM-main, and restart it in case of failure/shutdown. IM-angel is - started only if startup option '--run-as-service' is provided. - - IM-main consists of several subsystems (thread sets): - - - the signal handling thread - - The signal thread handles user signals and propagates them to the - other threads. All other threads are accounted in the signal handler - thread Thread Registry. - - - the listener - - The listener listens to all sockets. There is a listening socket for - each subsystem (TCP/IP, UNIX socket). - - - mysql subsystem - - Instance Manager acts like an ordinary MySQL Server, but with very - restricted command set. Each MySQL client connection is handled in a - separate thread. All MySQL client connections threads constitute - mysql subsystem. -*/ - -static int main_impl(int argc, char *argv[]); - -#ifndef __WIN__ -static struct passwd *check_user(); -static bool switch_user(); -#endif - - -/************************************************************************/ -/** - The entry point. -*************************************************************************/ - -int main(int argc, char *argv[]) -{ - int return_value; - - puts("\n" - "WARNING: This program is deprecated and will be removed in 6.0.\n"); - - /* Initialize. */ - - MY_INIT(argv[0]); - log_init(); - umask(0117); - srand((uint) time(0)); - - /* Main function. */ - - log_info("IM: started."); - - return_value= main_impl(argc, argv); - - log_info("IM: finished."); - - /* Cleanup. */ - - Options::cleanup(); - my_end(0); - - return return_value; -} - - -/************************************************************************/ -/** - Instance Manager main functionality. -*************************************************************************/ - -int main_impl(int argc, char *argv[]) -{ - int rc; - - if ((rc= Options::load(argc, argv))) - return rc; - - if (Options::User_management::cmd) - return Options::User_management::cmd->execute(); - -#ifndef __WIN__ - - if (switch_user()) - return 1; - - return Options::Daemon::run_as_service ? - Angel::main() : - Manager::main(); - -#else - - return Options::Service::stand_alone ? - Manager::main() : - IMService::main(); - -#endif -} - -/************************************************************************** - OS-specific functions implementation. -**************************************************************************/ - -#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) - -/************************************************************************/ -/** - Change to run as another user if started with --user. -*************************************************************************/ - -static struct passwd *check_user() -{ - const char *user= Options::Daemon::user; - struct passwd *user_info; - uid_t user_id= geteuid(); - - /* Don't bother if we aren't superuser */ - if (user_id) - { - if (user) - { - /* Don't give a warning, if real user is same as given with --user */ - user_info= getpwnam(user); - if ((!user_info || user_id != user_info->pw_uid)) - log_info("One can only use the --user switch if running as root\n"); - } - return NULL; - } - if (!user) - { - log_info("You are running mysqlmanager as root! This might introduce security problems. It is safer to use --user option istead.\n"); - return NULL; - } - if (!strcmp(user, "root")) - return NULL; /* Avoid problem with dynamic libraries */ - if (!(user_info= getpwnam(user))) - { - /* Allow a numeric uid to be used */ - const char *pos; - for (pos= user; my_isdigit(default_charset_info, *pos); pos++) - {} - if (*pos) /* Not numeric id */ - goto err; - if (!(user_info= getpwuid(atoi(user)))) - goto err; - else - return user_info; - } - else - return user_info; - -err: - log_error("Can not start under user '%s'.", - (const char *) user); - return NULL; -} - - -/************************************************************************/ -/** - Switch user. -*************************************************************************/ - -static bool switch_user() -{ - struct passwd *user_info= check_user(); - - if (!user_info) - return FALSE; - -#ifdef HAVE_INITGROUPS - initgroups(Options::Daemon::user, user_info->pw_gid); -#endif - - if (setgid(user_info->pw_gid) == -1) - { - log_error("setgid() failed"); - return TRUE; - } - - if (setuid(user_info->pw_uid) == -1) - { - log_error("setuid() failed"); - return TRUE; - } - - return FALSE; -} - -#endif diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc deleted file mode 100644 index ebca593bb03..00000000000 --- a/server-tools/instance-manager/options.cc +++ /dev/null @@ -1,558 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "options.h" - -#include -#include -#include -#include - -#include "exit_codes.h" -#include "log.h" -#include "portability.h" -#include "priv.h" -#include "user_management_commands.h" - -#define QUOTE2(x) #x -#define QUOTE(x) QUOTE2(x) - -#ifdef __WIN__ - -/* Define holders for default values. */ - -static char win_dflt_config_file_name[FN_REFLEN]; -static char win_dflt_password_file_name[FN_REFLEN]; -static char win_dflt_pid_file_name[FN_REFLEN]; - -static char win_dflt_mysqld_path[FN_REFLEN]; - -/* Define and initialize Windows-specific options. */ - -my_bool Options::Service::install_as_service; -my_bool Options::Service::remove_service; -my_bool Options::Service::stand_alone; - -const char *Options::Main::config_file= win_dflt_config_file_name; -const char *Options::Main::password_file_name= win_dflt_password_file_name; -const char *Options::Main::pid_file_name= win_dflt_pid_file_name; - -const char *Options::Main::default_mysqld_path= win_dflt_mysqld_path; - -static int setup_windows_defaults(); - -#else /* UNIX */ - -/* Define and initialize UNIX-specific options. */ - -my_bool Options::Daemon::run_as_service= FALSE; -const char *Options::Daemon::log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME); -const char *Options::Daemon::user= NULL; /* No default value */ -const char *Options::Daemon::angel_pid_file_name= NULL; - -const char *Options::Main::config_file= QUOTE(DEFAULT_CONFIG_FILE); -const char * -Options::Main::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); -const char *Options::Main::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME); -const char *Options::Main::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME); - -const char *Options::Main::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH); - -#endif - -/* Remember if the config file was forced. */ - -bool Options::Main::is_forced_default_file= FALSE; - -/* Define and initialize common options. */ - -const char *Options::Main::bind_address= NULL; /* No default value */ -uint Options::Main::monitoring_interval= DEFAULT_MONITORING_INTERVAL; -uint Options::Main::port_number= DEFAULT_PORT; -my_bool Options::Main::mysqld_safe_compatible= FALSE; -const char **Options::default_directories= NULL; - -/* Options::User_management */ - -char *Options::User_management::user_name= NULL; -char *Options::User_management::password= NULL; - -User_management_cmd *Options::User_management::cmd= NULL; - -/* Private members. */ - -char **Options::saved_argv= NULL; - -#ifndef DBUG_OFF -const char *Options::Debug::config_str= "d:t:i:O,im.trace"; -#endif - -static const char * const ANGEL_PID_FILE_SUFFIX= ".angel.pid"; -static const int ANGEL_PID_FILE_SUFFIX_LEN= (uint) strlen(ANGEL_PID_FILE_SUFFIX); - -/* - List of options, accepted by the instance manager. - List must be closed with empty option. -*/ - -enum options { - OPT_USERNAME= 'u', - OPT_PASSWORD= 'p', - OPT_LOG= 256, - OPT_PID_FILE, - OPT_SOCKET, - OPT_PASSWORD_FILE, - OPT_MYSQLD_PATH, -#ifdef __WIN__ - OPT_INSTALL_SERVICE, - OPT_REMOVE_SERVICE, - OPT_STAND_ALONE, -#else - OPT_RUN_AS_SERVICE, - OPT_USER, - OPT_ANGEL_PID_FILE, -#endif - OPT_MONITORING_INTERVAL, - OPT_PORT, - OPT_WAIT_TIMEOUT, - OPT_BIND_ADDRESS, - OPT_PRINT_PASSWORD_LINE, - OPT_ADD_USER, - OPT_DROP_USER, - OPT_EDIT_USER, - OPT_CLEAN_PASSWORD_FILE, - OPT_CHECK_PASSWORD_FILE, - OPT_LIST_USERS, - OPT_MYSQLD_SAFE_COMPATIBLE -}; - -static struct my_option my_long_options[] = -{ - { "help", '?', "Display this help and exit.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "add-user", OPT_ADD_USER, - "Add a user to the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifndef __WIN__ - { "angel-pid-file", OPT_ANGEL_PID_FILE, "Pid file for angel process.", - (uchar* *) &Options::Daemon::angel_pid_file_name, - (uchar* *) &Options::Daemon::angel_pid_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - - { "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.", - (uchar* *) &Options::Main::bind_address, - (uchar* *) &Options::Main::bind_address, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "check-password-file", OPT_CHECK_PASSWORD_FILE, - "Check the password file for consistency", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "clean-password-file", OPT_CLEAN_PASSWORD_FILE, - "Clean the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifndef DBUG_OFF - {"debug", '#', "Debug log.", - (uchar* *) &Options::Debug::config_str, - (uchar* *) &Options::Debug::config_str, - 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, -#endif - - { "default-mysqld-path", OPT_MYSQLD_PATH, "Where to look for MySQL" - " Server binary.", - (uchar* *) &Options::Main::default_mysqld_path, - (uchar* *) &Options::Main::default_mysqld_path, - 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 }, - - { "drop-user", OPT_DROP_USER, - "Drop existing user from the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "edit-user", OPT_EDIT_USER, - "Edit existing user in the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifdef __WIN__ - { "install", OPT_INSTALL_SERVICE, "Install as system service.", - (uchar* *) &Options::Service::install_as_service, - (uchar* *) &Options::Service::install_as_service, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 }, -#endif - - { "list-users", OPT_LIST_USERS, - "Print out a list of registered users", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifndef __WIN__ - { "log", OPT_LOG, "Path to log file. Used only with --run-as-service.", - (uchar* *) &Options::Daemon::log_file_name, - (uchar* *) &Options::Daemon::log_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - - { "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor" - " instances in seconds.", - (uchar* *) &Options::Main::monitoring_interval, - (uchar* *) &Options::Main::monitoring_interval, - 0, GET_UINT, REQUIRED_ARG, DEFAULT_MONITORING_INTERVAL, - 0, 0, 0, 0, 0 }, - - { "mysqld-safe-compatible", OPT_MYSQLD_SAFE_COMPATIBLE, - "Start Instance Manager in mysqld_safe compatible manner", - (uchar* *) &Options::Main::mysqld_safe_compatible, - (uchar* *) &Options::Main::mysqld_safe_compatible, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 }, - - { "print-password-line", OPT_PRINT_PASSWORD_LINE, - "Print out a user entry as a line for the password file and exit.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "password", OPT_PASSWORD, "Password to update the password file", - (uchar* *) &Options::User_management::password, - (uchar* *) &Options::User_management::password, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "password-file", OPT_PASSWORD_FILE, - "Look for Instance Manager users and passwords here.", - (uchar* *) &Options::Main::password_file_name, - (uchar* *) &Options::Main::password_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "pid-file", OPT_PID_FILE, "Pid file to use.", - (uchar* *) &Options::Main::pid_file_name, - (uchar* *) &Options::Main::pid_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "port", OPT_PORT, "Port number to use for connections", - (uchar* *) &Options::Main::port_number, - (uchar* *) &Options::Main::port_number, - 0, GET_UINT, REQUIRED_ARG, DEFAULT_PORT, 0, 0, 0, 0, 0 }, - -#ifdef __WIN__ - { "remove", OPT_REMOVE_SERVICE, "Remove system service.", - (uchar* *) &Options::Service::remove_service, - (uchar* *) &Options::Service::remove_service, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0}, -#else - { "run-as-service", OPT_RUN_AS_SERVICE, - "Daemonize and start angel process.", - (uchar* *) &Options::Daemon::run_as_service, - 0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 }, -#endif - -#ifndef __WIN__ - { "socket", OPT_SOCKET, "Socket file to use for connection.", - (uchar* *) &Options::Main::socket_file_name, - (uchar* *) &Options::Main::socket_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - -#ifdef __WIN__ - { "standalone", OPT_STAND_ALONE, "Run the application in stand alone mode.", - (uchar* *) &Options::Service::stand_alone, - (uchar* *) &Options::Service::stand_alone, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0}, -#else - { "user", OPT_USER, "Username to start mysqlmanager", - (uchar* *) &Options::Daemon::user, - (uchar* *) &Options::Daemon::user, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - - { "username", OPT_USERNAME, - "Username to update the password file", - (uchar* *) &Options::User_management::user_name, - (uchar* *) &Options::User_management::user_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "version", 'V', "Output version information and exit.", 0, 0, 0, - GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "wait-timeout", OPT_WAIT_TIMEOUT, "The number of seconds IM waits " - "for activity on a connection before closing it.", - (uchar* *) &net_read_timeout, - (uchar* *) &net_read_timeout, - 0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 }, - - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 } -}; - -static void version() -{ - printf("%s Ver %s for %s on %s\n", my_progname, - (const char *) mysqlmanager_version.str, - SYSTEM_TYPE, MACHINE_TYPE); -} - - -static const char *default_groups[]= { "manager", 0 }; - - -static void usage() -{ - version(); - - printf("Copyright (C) 2003, 2004 MySQL AB\n" - "This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n" - "and you are welcome to modify and redistribute it under the GPL license\n"); - printf("Usage: %s [OPTIONS] \n", my_progname); - - my_print_help(my_long_options); - printf("\nThe following options may be given as the first argument:\n" - "--print-defaults Print the program argument list and exit\n" - "--defaults-file=# Only read manager configuration and instance\n" - " setings from the given file #. The same file\n" - " will be used to modify configuration of instances\n" - " with SET commands.\n"); - my_print_variables(my_long_options); -} - - -C_MODE_START - -static my_bool -get_one_option(int optid, - const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch(optid) { - case 'V': - version(); - exit(0); - case OPT_PRINT_PASSWORD_LINE: - case OPT_ADD_USER: - case OPT_DROP_USER: - case OPT_EDIT_USER: - case OPT_CLEAN_PASSWORD_FILE: - case OPT_CHECK_PASSWORD_FILE: - case OPT_LIST_USERS: - if (Options::User_management::cmd) - { - fprintf(stderr, "Error: only one password-management command " - "can be specified at a time.\n"); - exit(ERR_INVALID_USAGE); - } - - switch (optid) { - case OPT_PRINT_PASSWORD_LINE: - Options::User_management::cmd= new Print_password_line_cmd(); - break; - case OPT_ADD_USER: - Options::User_management::cmd= new Add_user_cmd(); - break; - case OPT_DROP_USER: - Options::User_management::cmd= new Drop_user_cmd(); - break; - case OPT_EDIT_USER: - Options::User_management::cmd= new Edit_user_cmd(); - break; - case OPT_CLEAN_PASSWORD_FILE: - Options::User_management::cmd= new Clean_db_cmd(); - break; - case OPT_CHECK_PASSWORD_FILE: - Options::User_management::cmd= new Check_db_cmd(); - break; - case OPT_LIST_USERS: - Options::User_management::cmd= new List_users_cmd(); - break; - } - - break; - case '?': - usage(); - exit(0); - case '#': -#ifndef DBUG_OFF - DBUG_SET(argument ? argument : Options::Debug::config_str); - DBUG_SET_INITIAL(argument ? argument : Options::Debug::config_str); -#endif - break; - } - return 0; -} - -C_MODE_END - - -/* - - Process argv of original program: get tid of --defaults-extra-file - and print a message if met there. - - call load_defaults to load configuration file section and save the pointer - for free_defaults. - - call handle_options to assign defaults and command-line arguments - to the class members. - if either of these function fail, return the error code. -*/ - -int Options::load(int argc, char **argv) -{ - if (argc >= 2) - { - if (is_prefix(argv[1], "--defaults-file=")) - { - Main::config_file= strchr(argv[1], '=') + 1; - Main::is_forced_default_file= TRUE; - } - if (is_prefix(argv[1], "--defaults-extra-file=") || - is_prefix(argv[1], "--no-defaults")) - { - /* the log is not enabled yet */ - fprintf(stderr, "The --defaults-extra-file and --no-defaults options" - " are not supported by\n" - "Instance Manager. Program aborted.\n"); - return ERR_INVALID_USAGE; - } - } - -#ifdef __WIN__ - if (setup_windows_defaults()) - { - fprintf(stderr, "Internal error: could not setup default values.\n"); - return ERR_OUT_OF_MEMORY; - } -#endif - - /* load_defaults will reset saved_argv with a new allocated list */ - saved_argv= argv; - - /* config-file options are prepended to command-line ones */ - - log_info("Loading config file '%s'...", - (const char *) Main::config_file); - - my_load_defaults(Main::config_file, default_groups, &argc, - &saved_argv, &default_directories); - - if ((handle_options(&argc, &saved_argv, my_long_options, get_one_option))) - return ERR_INVALID_USAGE; - - if (!User_management::cmd && - (User_management::user_name || User_management::password)) - { - fprintf(stderr, - "--username and/or --password options have been specified, " - "but no password-management command has been given.\n"); - return ERR_INVALID_USAGE; - } - -#ifndef __WIN__ - if (Options::Daemon::run_as_service) - { - if (Options::Daemon::angel_pid_file_name == NULL) - { - /* - Calculate angel pid file on the IM pid file basis: replace the - extension (everything after the last dot) of the pid file basename to - '.angel.pid'. - */ - - char *local_angel_pid_file_name; - char *base_name_ptr; - char *ext_ptr; - - local_angel_pid_file_name= - (char *) malloc(strlen(Options::Main::pid_file_name) + - ANGEL_PID_FILE_SUFFIX_LEN); - - strcpy(local_angel_pid_file_name, Options::Main::pid_file_name); - - base_name_ptr= strrchr(local_angel_pid_file_name, '/'); - - if (!base_name_ptr) - base_name_ptr= local_angel_pid_file_name + 1; - - ext_ptr= strrchr(base_name_ptr, '.'); - if (ext_ptr) - *ext_ptr= 0; - - strcat(local_angel_pid_file_name, ANGEL_PID_FILE_SUFFIX); - - Options::Daemon::angel_pid_file_name= local_angel_pid_file_name; - } - else - { - Options::Daemon::angel_pid_file_name= - strdup(Options::Daemon::angel_pid_file_name); - } - } -#endif - - return 0; -} - -void Options::cleanup() -{ - if (saved_argv) - free_defaults(saved_argv); - - delete User_management::cmd; - -#ifndef __WIN__ - if (Options::Daemon::run_as_service) - free((void *) Options::Daemon::angel_pid_file_name); -#endif -} - -#ifdef __WIN__ - -static int setup_windows_defaults() -{ - char module_full_name[FN_REFLEN]; - char dir_name[FN_REFLEN]; - char base_name[FN_REFLEN]; - char im_name[FN_REFLEN]; - char *base_name_ptr; - char *ptr; - - /* Determine dirname and basename. */ - - if (!GetModuleFileName(NULL, module_full_name, sizeof (module_full_name)) || - !GetFullPathName(module_full_name, sizeof (dir_name), dir_name, - &base_name_ptr)) - { - return 1; - } - - strmake(base_name, base_name_ptr, FN_REFLEN); - *base_name_ptr= 0; - - strmake(im_name, base_name, FN_REFLEN); - ptr= strrchr(im_name, '.'); - - if (!ptr) - return 1; - - *ptr= 0; - - /* Initialize the defaults. */ - - strxmov(win_dflt_config_file_name, dir_name, DFLT_CONFIG_FILE_NAME, NullS); - strxmov(win_dflt_mysqld_path, dir_name, DFLT_MYSQLD_PATH, NullS); - strxmov(win_dflt_password_file_name, dir_name, im_name, DFLT_PASSWD_FILE_EXT, - NullS); - strxmov(win_dflt_pid_file_name, dir_name, im_name, DFLT_PID_FILE_EXT, NullS); - - return 0; -} - -#endif diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h deleted file mode 100644 index 5d4df51faae..00000000000 --- a/server-tools/instance-manager/options.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H - -/* - Options - all possible command-line options for the Instance Manager grouped - in one struct. -*/ - -#include - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class User_management_cmd; - -struct Options -{ - /* - NOTE: handle_options() expects value of my_bool type for GET_BOOL - accessor (i.e. bool must not be used). - */ - - struct User_management - { - static User_management_cmd *cmd; - - static char *user_name; - static char *password; - }; - - struct Main - { - /* this is not an option parsed by handle_options(). */ - static bool is_forced_default_file; - - static const char *pid_file_name; -#ifndef __WIN__ - static const char *socket_file_name; -#endif - static const char *password_file_name; - static const char *default_mysqld_path; - static uint monitoring_interval; - static uint port_number; - static const char *bind_address; - static const char *config_file; - static my_bool mysqld_safe_compatible; - }; - -#ifndef DBUG_OFF - struct Debug - { - static const char *config_str; - }; -#endif - -#ifndef __WIN__ - - struct Daemon - { - static my_bool run_as_service; - static const char *log_file_name; - static const char *user; - static const char *angel_pid_file_name; - }; - -#else - - struct Service - { - static my_bool install_as_service; - static my_bool remove_service; - static my_bool stand_alone; - }; - -#endif - -public: - /* Array of paths to be passed to my_search_option_files() later */ - static const char **default_directories; - - static int load(int argc, char **argv); - static void cleanup(); - -private: - Options(); /* Deny instantiation of this class. */ - -private: - /* argv pointer returned by load_defaults() to be used by free_defaults() */ - static char **saved_argv; -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc deleted file mode 100644 index cd20e3bc7ab..00000000000 --- a/server-tools/instance-manager/parse.cc +++ /dev/null @@ -1,509 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "parse.h" -#include "commands.h" - - -enum Token -{ - TOK_CREATE= 0, - TOK_DROP, - TOK_ERROR, /* Encodes the "ERROR" word, it doesn't indicate error. */ - TOK_FILES, - TOK_FLUSH, - TOK_GENERAL, - TOK_INSTANCE, - TOK_INSTANCES, - TOK_LOG, - TOK_OPTIONS, - TOK_SET, - TOK_SLOW, - TOK_START, - TOK_STATUS, - TOK_STOP, - TOK_SHOW, - TOK_UNSET, - TOK_NOT_FOUND, // must be after all tokens - TOK_END -}; - - -struct tokens_st -{ - uint length; - const char *tok_name; -}; - - -static struct tokens_st tokens[]= { - {6, "CREATE"}, - {4, "DROP"}, - {5, "ERROR"}, - {5, "FILES"}, - {5, "FLUSH"}, - {7, "GENERAL"}, - {8, "INSTANCE"}, - {9, "INSTANCES"}, - {3, "LOG"}, - {7, "OPTIONS"}, - {3, "SET"}, - {4, "SLOW"}, - {5, "START"}, - {6, "STATUS"}, - {4, "STOP"}, - {4, "SHOW"}, - {5, "UNSET"} -}; - -/************************************************************************/ - -Named_value_arr::Named_value_arr() : - initialized(FALSE) -{ -} - - -bool Named_value_arr::init() -{ - if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32)) - return TRUE; - - initialized= TRUE; - - return FALSE; -} - - -Named_value_arr::~Named_value_arr() -{ - if (!initialized) - return; - - for (int i= 0; i < get_size(); ++i) - get_element(i).free(); - - delete_dynamic(&arr); -} - -/************************************************************************/ - -/* - Returns token no if word corresponds to some token, otherwise returns - TOK_NOT_FOUND -*/ - -inline Token find_token(const char *word, size_t word_len) -{ - int i= 0; - do - { - if (my_strnncoll(default_charset_info, (const uchar *) tokens[i].tok_name, - tokens[i].length, (const uchar *) word, word_len) == 0) - break; - } - while (++i < TOK_NOT_FOUND); - return (Token) i; -} - - -Token get_token(const char **text, size_t *word_len) -{ - get_word(text, word_len); - if (*word_len) - return find_token(*text, *word_len); - return TOK_END; -} - - -Token shift_token(const char **text, size_t *word_len) -{ - Token save= get_token(text, word_len); - (*text)+= *word_len; - return save; -} - - -int get_text_id(const char **text, LEX_STRING *token) -{ - get_word(text, &token->length); - if (token->length == 0) - return 1; - token->str= (char *) *text; - return 0; -} - - -static bool parse_long(const LEX_STRING *token, long *value) -{ - int err_code; - char *end_ptr= token->str + token->length; - - *value= (long)my_strtoll10(token->str, &end_ptr, &err_code); - - return err_code != 0; -} - - -bool parse_option_value(const char *text, size_t *text_len, char **value) -{ - char beginning_quote; - const char *text_start_ptr; - char *v; - bool escape_mode= FALSE; - - if (!*text || (*text != '\'' && *text != '"')) - return TRUE; /* syntax error: string expected. */ - - beginning_quote= *text; - - ++text; /* skip the beginning quote. */ - - text_start_ptr= text; - - if (!(v= Named_value::alloc_str(text))) - return TRUE; - - *value= v; - - while (TRUE) - { - if (!*text) - { - Named_value::free_str(value); - return TRUE; /* syntax error: missing terminating ' character. */ - } - - if (*text == '\n' || *text == '\r') - { - Named_value::free_str(value); - return TRUE; /* syntax error: option value should be a single line. */ - } - - if (!escape_mode && *text == beginning_quote) - break; - - if (escape_mode) - { - switch (*text) - { - case 'b': /* \b -- backspace */ - if (v > *value) - --v; - break; - - case 't': /* \t -- tab */ - *v= '\t'; - ++v; - break; - - case 'n': /* \n -- newline */ - *v= '\n'; - ++v; - break; - - case 'r': /* \r -- carriage return */ - *v= '\r'; - ++v; - break; - - case '\\': /* \\ -- back slash */ - *v= '\\'; - ++v; - break; - - case 's': /* \s -- space */ - *v= ' '; - ++v; - break; - - default: /* Unknown escape sequence. Treat as error. */ - Named_value::free_str(value); - return TRUE; - } - - escape_mode= FALSE; - } - else - { - if (*text == '\\') - { - escape_mode= TRUE; - } - else - { - *v= *text; - ++v; - } - } - - ++text; - } - - *v= 0; - - /* "2" below stands for beginning and ending quotes. */ - *text_len= text - text_start_ptr + 2; - - return FALSE; -} - - -void skip_spaces(const char **text) -{ - while (**text && my_isspace(default_charset_info, **text)) - ++(*text); -} - - -Command *parse_command(const char *text) -{ - size_t word_len; - LEX_STRING instance_name; - Command *command= 0; - - Token tok1= shift_token(&text, &word_len); - - switch (tok1) { - case TOK_START: // fallthrough - case TOK_STOP: - case TOK_CREATE: - case TOK_DROP: - if (shift_token(&text, &word_len) != TOK_INSTANCE) - goto syntax_error; - get_word(&text, &word_len); - if (word_len == 0) - goto syntax_error; - instance_name.str= (char *) text; - instance_name.length= word_len; - text+= word_len; - - if (tok1 == TOK_CREATE) - { - Create_instance *cmd= new Create_instance(&instance_name); - - if (!cmd) - return NULL; /* Report ER_OUT_OF_RESOURCES. */ - - if (cmd->init(&text)) - { - delete cmd; - goto syntax_error; - } - - command= cmd; - } - else - { - /* it should be the end of command */ - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - } - - switch (tok1) { - case TOK_START: - command= new Start_instance(&instance_name); - break; - case TOK_STOP: - command= new Stop_instance(&instance_name); - break; - case TOK_CREATE: - ; /* command already initialized. */ - break; - case TOK_DROP: - command= new Drop_instance(&instance_name); - break; - default: /* this is impossible, but nevertheless... */ - DBUG_ASSERT(0); - } - break; - case TOK_FLUSH: - if (shift_token(&text, &word_len) != TOK_INSTANCES) - goto syntax_error; - - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - - command= new Flush_instances(); - break; - case TOK_UNSET: - case TOK_SET: - { - Abstract_option_cmd *cmd; - - if (tok1 == TOK_SET) - cmd= new Set_option(); - else - cmd= new Unset_option(); - - if (!cmd) - return NULL; /* Report ER_OUT_OF_RESOURCES. */ - - if (cmd->init(&text)) - { - delete cmd; - goto syntax_error; - } - - command= cmd; - - break; - } - case TOK_SHOW: - switch (shift_token(&text, &word_len)) { - case TOK_INSTANCES: - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - command= new Show_instances(); - break; - case TOK_INSTANCE: - switch (Token tok2= shift_token(&text, &word_len)) { - case TOK_OPTIONS: - case TOK_STATUS: - if (get_text_id(&text, &instance_name)) - goto syntax_error; - text+= instance_name.length; - /* check that this is the end of the command */ - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - if (tok2 == TOK_STATUS) - command= new Show_instance_status(&instance_name); - else - command= new Show_instance_options(&instance_name); - break; - default: - goto syntax_error; - } - break; - default: - instance_name.str= (char *) text - word_len; - instance_name.length= word_len; - if (instance_name.length) - { - Log_type log_type; - - long log_size; - LEX_STRING log_size_str; - - long log_offset= 0; - LEX_STRING log_offset_str= { NULL, 0 }; - - switch (shift_token(&text, &word_len)) { - case TOK_LOG: - switch (Token tok3= shift_token(&text, &word_len)) { - case TOK_FILES: - get_word(&text, &word_len, NONSPACE); - /* check that this is the end of the command */ - if (word_len) - goto syntax_error; - command= new Show_instance_log_files(&instance_name); - break; - case TOK_ERROR: - case TOK_GENERAL: - case TOK_SLOW: - /* define a log type */ - switch (tok3) { - case TOK_ERROR: - log_type= IM_LOG_ERROR; - break; - case TOK_GENERAL: - log_type= IM_LOG_GENERAL; - break; - case TOK_SLOW: - log_type= IM_LOG_SLOW; - break; - default: - goto syntax_error; - } - /* get the size of the log we want to retrieve */ - if (get_text_id(&text, &log_size_str)) - goto syntax_error; - text+= log_size_str.length; - - /* this parameter is required */ - if (!log_size_str.length) - goto syntax_error; - - /* the next token should be comma, or nothing */ - get_word(&text, &word_len); - switch (*text) { - case ',': - text++; /* swallow the comma */ - /* read the next word */ - get_word(&text, &word_len); - if (!word_len) - goto syntax_error; - log_offset_str.str= (char *) text; - log_offset_str.length= word_len; - text+= word_len; - get_word(&text, &word_len, NONSPACE); - /* check that this is the end of the command */ - if (word_len) - goto syntax_error; - break; - case '\0': - break; /* this is ok */ - default: - goto syntax_error; - } - - /* Parse size parameter. */ - - if (parse_long(&log_size_str, &log_size)) - goto syntax_error; - - if (log_size <= 0) - goto syntax_error; - - /* Parse offset parameter (if specified). */ - - if (log_offset_str.length) - { - if (parse_long(&log_offset_str, &log_offset)) - goto syntax_error; - - if (log_offset <= 0) - goto syntax_error; - } - - command= new Show_instance_log(&instance_name, - log_type, log_size, log_offset); - break; - default: - goto syntax_error; - } - break; - default: - goto syntax_error; - } - } - else - goto syntax_error; - break; - } - break; - default: -syntax_error: - command= new Syntax_error(); - } - - DBUG_ASSERT(command); - - return command; -} diff --git a/server-tools/instance-manager/parse.h b/server-tools/instance-manager/parse.h deleted file mode 100644 index 9c50ace5948..00000000000 --- a/server-tools/instance-manager/parse.h +++ /dev/null @@ -1,212 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include -#include -#include - -class Command; - -enum Log_type -{ - IM_LOG_ERROR= 0, - IM_LOG_GENERAL, - IM_LOG_SLOW -}; - -Command *parse_command(const char *text); - -bool parse_option_value(const char *text, size_t *text_len, char **value); - -void skip_spaces(const char **text); - -/* define kinds of the word seek method */ -enum enum_seek_method { ALPHANUM= 1, NONSPACE, OPTION_NAME }; - -/************************************************************************/ - -class Named_value -{ -public: - /* - The purpose of these methods is just to have one method for - allocating/deallocating memory for strings for Named_value. - */ - - static inline char *alloc_str(const LEX_STRING *str); - static inline char *alloc_str(const char *str); - static inline void free_str(char **str); - -public: - inline Named_value(); - inline Named_value(char *name_arg, char *value_arg); - - inline char *get_name(); - inline char *get_value(); - - inline void free(); - -private: - char *name; - char *value; -}; - -inline char *Named_value::alloc_str(const LEX_STRING *str) -{ - return my_strndup(str->str, str->length, MYF(0)); -} - -inline char *Named_value::alloc_str(const char *str) -{ - return my_strdup(str, MYF(0)); -} - -inline void Named_value::free_str(char **str) -{ - my_free(*str, MYF(MY_ALLOW_ZERO_PTR)); - *str= NULL; -} - -inline Named_value::Named_value() - :name(NULL), value(NULL) -{ } - -inline Named_value::Named_value(char *name_arg, char *value_arg) - :name(name_arg), value(value_arg) -{ } - -inline char *Named_value::get_name() -{ - return name; -} - -inline char *Named_value::get_value() -{ - return value; -} - -void Named_value::free() -{ - free_str(&name); - free_str(&value); -} - -/************************************************************************/ - -class Named_value_arr -{ -public: - Named_value_arr(); - ~Named_value_arr(); - - bool init(); - - inline int get_size() const; - inline Named_value get_element(int idx) const; - inline void remove_element(int idx); - inline bool add_element(Named_value *option); - inline bool replace_element(int idx, Named_value *option); - -private: - bool initialized; - DYNAMIC_ARRAY arr; -}; - - -inline int Named_value_arr::get_size() const -{ - return arr.elements; -} - - -inline Named_value Named_value_arr::get_element(int idx) const -{ - DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements); - - Named_value option; - get_dynamic((DYNAMIC_ARRAY *) &arr, (uchar*) &option, idx); - - return option; -} - - -inline void Named_value_arr::remove_element(int idx) -{ - DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements); - - get_element(idx).free(); - - delete_dynamic_element(&arr, idx); -} - - -inline bool Named_value_arr::add_element(Named_value *option) -{ - return insert_dynamic(&arr, (uchar*) option); -} - - -inline bool Named_value_arr::replace_element(int idx, Named_value *option) -{ - DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements); - - get_element(idx).free(); - - return set_dynamic(&arr, (uchar*) option, idx); -} - -/************************************************************************/ - -/* - tries to find next word in the text - if found, returns the beginning and puts word length to word_len argument. - if not found returns pointer to first non-space or to '\0', word_len == 0 -*/ - -inline void get_word(const char **text, size_t *word_len, - enum_seek_method seek_method= ALPHANUM) -{ - const char *word_end; - - /* skip space */ - while (my_isspace(default_charset_info, **text)) - ++(*text); - - word_end= *text; - - switch (seek_method) { - case ALPHANUM: - while (my_isalnum(default_charset_info, *word_end)) - ++word_end; - break; - case NONSPACE: - while (!my_isspace(default_charset_info, *word_end) && - (*word_end != '\0')) - ++word_end; - break; - case OPTION_NAME: - while (my_isalnum(default_charset_info, *word_end) || - *word_end == '-' || - *word_end == '_') - ++word_end; - break; - } - - *word_len= (uint) (word_end - *text); -} - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */ diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc deleted file mode 100644 index 3511589acd6..00000000000 --- a/server-tools/instance-manager/parse_output.cc +++ /dev/null @@ -1,407 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "parse_output.h" - -#include -#include -#include - -#include - -#include "parse.h" -#include "portability.h" - -/************************************************************************** - Private module implementation. -**************************************************************************/ - -namespace { /* no-indent */ - -/*************************************************************************/ - -void trim_space(const char **text, uint *word_len) -{ - const char *start= *text; - while (*start != 0 && *start == ' ') - start++; - *text= start; - - int len= strlen(start); - const char *end= start + len - 1; - while (end > start && my_isspace(&my_charset_latin1, *end)) - end--; - *word_len= (end - start)+1; -} - -/*************************************************************************/ - -/** - @brief A facade to the internal workings of optaining the output from an - executed system process. -*/ - -class Mysqld_output_parser -{ -public: - Mysqld_output_parser() - { } - - virtual ~Mysqld_output_parser() - { } - -public: - bool parse(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type); - -protected: - /** - @brief Run a process and attach stdout- and stdin-pipes to it. - - @param command The path to the process to be executed - - @return Error status. - @retval TRUE An error occurred - @retval FALSE Operation was a success - */ - - virtual bool run_command(const char *command)= 0; - - - /** - @brief Read a sequence of bytes from the executed process' stdout pipe. - - The sequence is terminated by either '\0', LF or CRLF tokens. The - terminating token is excluded from the result. - - @param line_buffer A pointer to a character buffer - @param line_buffer_size The size of the buffer in bytes - - @return Error status. - @retval TRUE An error occured - @retval FALSE Operation was a success - */ - - virtual bool read_line(char *line_buffer, - uint line_buffer_size)= 0; - - - /** - @brief Release any resources needed after a execution and parsing. - */ - - virtual bool cleanup()= 0; -}; - -/*************************************************************************/ - -bool Mysqld_output_parser::parse(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type) -{ - /* should be enough to store the string from the output */ - const int LINE_BUFFER_SIZE= 512; - char line_buffer[LINE_BUFFER_SIZE]; - - if (run_command(command)) - return TRUE; - - while (true) - { - if (read_line(line_buffer, LINE_BUFFER_SIZE)) - { - cleanup(); - return TRUE; - } - - uint found_word_len= 0; - char *linep= line_buffer; - - line_buffer[sizeof(line_buffer) - 1]= '\0'; /* safety */ - - /* Find the word(s) we are looking for in the line. */ - - linep= strstr(linep, option_name_str); - - if (!linep) - continue; - - linep+= option_name_length; - - switch (option_type) - { - case GET_VALUE: - trim_space((const char**) &linep, &found_word_len); - - if (option_value_buf_size <= found_word_len) - { - cleanup(); - return TRUE; - } - - strmake(option_value_buf, linep, found_word_len); - - break; - - case GET_LINE: - strmake(option_value_buf, linep, option_value_buf_size - 1); - - break; - } - - cleanup(); - - return FALSE; - } -} - -/************************************************************************** - Platform-specific implementation: UNIX. -**************************************************************************/ - -#ifndef __WIN__ - -class Mysqld_output_parser_unix : public Mysqld_output_parser -{ -public: - Mysqld_output_parser_unix() : - m_stdout(NULL) - { } - -protected: - virtual bool run_command(const char *command); - - virtual bool read_line(char *line_buffer, - uint line_buffer_size); - - virtual bool cleanup(); - -private: - FILE *m_stdout; -}; - -bool Mysqld_output_parser_unix::run_command(const char *command) -{ - if (!(m_stdout= popen(command, "r"))) - return TRUE; - - /* - We want fully buffered stream. We also want system to allocate - appropriate buffer. - */ - - setvbuf(m_stdout, NULL, _IOFBF, 0); - - return FALSE; -} - -bool Mysqld_output_parser_unix::read_line(char *line_buffer, - uint line_buffer_size) -{ - char *retbuff = fgets(line_buffer, line_buffer_size, m_stdout); - /* Remove any tailing new line charaters */ - if (line_buffer[line_buffer_size-1] == LF) - line_buffer[line_buffer_size-1]= '\0'; - return (retbuff == NULL); -} - -bool Mysqld_output_parser_unix::cleanup() -{ - if (m_stdout) - pclose(m_stdout); - - return FALSE; -} - -#else /* Windows */ - -/************************************************************************** - Platform-specific implementation: Windows. -**************************************************************************/ - -class Mysqld_output_parser_win : public Mysqld_output_parser -{ -public: - Mysqld_output_parser_win() : - m_internal_buffer(NULL), - m_internal_buffer_offset(0), - m_internal_buffer_size(0) - { } - -protected: - virtual bool run_command(const char *command); - virtual bool read_line(char *line_buffer, - uint line_buffer_size); - virtual bool cleanup(); - -private: - HANDLE m_h_child_stdout_wr; - HANDLE m_h_child_stdout_rd; - uint m_internal_buffer_offset; - uint m_internal_buffer_size; - char *m_internal_buffer; -}; - -bool Mysqld_output_parser_win::run_command(const char *command) -{ - BOOL op_status; - - SECURITY_ATTRIBUTES sa_attr; - sa_attr.nLength= sizeof(SECURITY_ATTRIBUTES); - sa_attr.bInheritHandle= TRUE; - sa_attr.lpSecurityDescriptor= NULL; - - op_status= CreatePipe(&m_h_child_stdout_rd, - &m_h_child_stdout_wr, - &sa_attr, - 0 /* Use system-default buffer size. */); - - if (!op_status) - return TRUE; - - SetHandleInformation(m_h_child_stdout_rd, HANDLE_FLAG_INHERIT, 0); - - STARTUPINFO si_start_info; - ZeroMemory(&si_start_info, sizeof(STARTUPINFO)); - si_start_info.cb= sizeof(STARTUPINFO); - si_start_info.hStdError= m_h_child_stdout_wr; - si_start_info.hStdOutput= m_h_child_stdout_wr; - si_start_info.dwFlags|= STARTF_USESTDHANDLES; - - PROCESS_INFORMATION pi_proc_info; - - op_status= CreateProcess(NULL, /* Application name. */ - (char*)command, /* Command line. */ - NULL, /* Process security attributes. */ - NULL, /* Primary thread security attr.*/ - TRUE, /* Handles are inherited. */ - 0, /* Creation flags. */ - NULL, /* Use parent's environment. */ - NULL, /* Use parent's curr. directory. */ - &si_start_info, /* STARTUPINFO pointer. */ - &pi_proc_info); /* Rec. PROCESS_INFORMATION. */ - - if (!op_status) - { - CloseHandle(m_h_child_stdout_rd); - CloseHandle(m_h_child_stdout_wr); - - return TRUE; - } - - /* Close unnessary handles. */ - - CloseHandle(pi_proc_info.hProcess); - CloseHandle(pi_proc_info.hThread); - - return FALSE; -} - -bool Mysqld_output_parser_win::read_line(char *line_buffer, - uint line_buffer_size) -{ - DWORD dw_read_count= m_internal_buffer_size; - bzero(line_buffer,line_buffer_size); - char *buff_ptr= line_buffer; - char ch; - - while ((unsigned)(buff_ptr - line_buffer) < line_buffer_size) - { - do - { - ReadFile(m_h_child_stdout_rd, &ch, - 1, &dw_read_count, NULL); - } while ((ch == CR || ch == LF) && buff_ptr == line_buffer); - - if (dw_read_count == 0) - return TRUE; - - if (ch == CR || ch == LF) - break; - - *buff_ptr++ = ch; - } - - return FALSE; -} - -bool Mysqld_output_parser_win::cleanup() -{ - /* Close all handles. */ - - CloseHandle(m_h_child_stdout_wr); - CloseHandle(m_h_child_stdout_rd); - - return FALSE; -} -#endif - -/*************************************************************************/ - -} /* End of private module implementation. */ - -/*************************************************************************/ - -/** - @brief Parse output of the given command - - @param command The command to execute. - @param option_name_str Option name. - @param option_name_length Length of the option name. - @param[out] option_value_buf The buffer to store option value. - @param option_value_buf_size Size of the option value buffer. - @param option_type Type of the option: - - GET_LINE if we want to get all the - line after the option name; - - GET_VALUE otherwise. - - Execute the process by running "command". Find the "option name" and - return the next word if "option_type" is GET_VALUE. Return the rest of - the parsed string otherwise. - - @note This function has a separate windows implementation. - - @return The error status. - @retval FALSE Ok, the option name has been found. - @retval TRUE Error occured or the option name is not found. -*/ - -bool parse_output_and_get_value(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type) -{ -#ifndef __WIN__ - Mysqld_output_parser_unix parser; -#else /* __WIN__ */ - Mysqld_output_parser_win parser; -#endif - - return parser.parse(command, - option_name_str, - option_name_length, - option_value_buf, - option_value_buf_size, - option_type); -} diff --git a/server-tools/instance-manager/parse_output.h b/server-tools/instance-manager/parse_output.h deleted file mode 100644 index 41618f643a3..00000000000 --- a/server-tools/instance-manager/parse_output.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include - -enum enum_option_type -{ - GET_VALUE = 1, - GET_LINE -}; - -bool parse_output_and_get_value(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type); - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H */ diff --git a/server-tools/instance-manager/portability.h b/server-tools/instance-manager/portability.h deleted file mode 100644 index 990e6140a9e..00000000000 --- a/server-tools/instance-manager/portability.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2005-2006 MySQL AB - - 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 */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H - -#if (defined(_SCO_DS) || defined(UNIXWARE_7)) && !defined(SHUT_RDWR) -/* - SHUT_* functions are defined only if - "(defined(_XOPEN_SOURCE) && _XOPEN_SOURCE_EXTENDED - 0 >= 1)" -*/ -#define SHUT_RDWR 2 -#endif - -#ifdef __WIN__ - -#define vsnprintf _vsnprintf -#define snprintf _snprintf - -#define SIGKILL 9 - -/*TODO: fix this */ -#define PROTOCOL_VERSION 10 - -#define DFLT_CONFIG_FILE_NAME "my.ini" -#define DFLT_MYSQLD_PATH "mysqld" -#define DFLT_PASSWD_FILE_EXT ".passwd" -#define DFLT_PID_FILE_EXT ".pid" -#define DFLT_SOCKET_FILE_EXT ".sock" - -typedef int pid_t; - -#undef popen -#define popen(A,B) _popen(A,B) - -#define NEWLINE "\r\n" -#define NEWLINE_LEN 2 - -const char CR = '\r'; -const char LF = '\n'; - -#else /* ! __WIN__ */ - -#define NEWLINE "\n" -#define NEWLINE_LEN 1 - -const char LF = '\n'; - -#endif /* __WIN__ */ - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H */ - - diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc deleted file mode 100644 index 74263934924..00000000000 --- a/server-tools/instance-manager/priv.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "priv.h" - -#include -#include -#include - -#include "log.h" - -/* - The following string must be less then 80 characters, as - mysql_connection.cc relies on it -*/ -const LEX_STRING mysqlmanager_version= { C_STRING_WITH_LEN("1.0-beta") }; - -const unsigned char protocol_version= PROTOCOL_VERSION; - -unsigned long net_buffer_length= 16384; - -unsigned long max_allowed_packet= 16384; - -unsigned long net_read_timeout= NET_WAIT_TIMEOUT; // same as in mysqld - -unsigned long net_write_timeout= 60; // same as in mysqld - -unsigned long net_retry_count= 10; // same as in mysqld - -/* needed by net_serv.cc */ -unsigned int test_flags= 0; -unsigned long bytes_sent = 0L, bytes_received = 0L; -unsigned long mysqld_net_retry_count = 10L; -unsigned long open_files_limit; - - - -bool create_pid_file(const char *pid_file_name, int pid) -{ - FILE *pid_file; - - if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY, - MYF(0)))) - { - log_error("Can not create pid file '%s': %s (errno: %d)", - (const char *) pid_file_name, - (const char *) strerror(errno), - (int) errno); - return TRUE; - } - - if (fprintf(pid_file, "%d\n", (int) pid) <= 0) - { - log_error("Can not write to pid file '%s': %s (errno: %d)", - (const char *) pid_file_name, - (const char *) strerror(errno), - (int) errno); - return TRUE; - } - - my_fclose(pid_file, MYF(0)); - - return FALSE; -} diff --git a/server-tools/instance-manager/priv.h b/server-tools/instance-manager/priv.h deleted file mode 100644 index 1c2124c0e77..00000000000 --- a/server-tools/instance-manager/priv.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H - -#include -#include -#include - -#include - -#ifndef __WIN__ -#include -#endif - -#include "portability.h" - -/* IM-wide platform-independent defines */ -#define SERVER_DEFAULT_PORT MYSQL_PORT -#define DEFAULT_MONITORING_INTERVAL 20 -#define DEFAULT_PORT 2273 -/* three-week timeout should be enough */ -#define LONG_TIMEOUT ((ulong) 3600L*24L*21L) - -const int MEM_ROOT_BLOCK_SIZE= 512; - -/* The maximal length of option name and option value. */ -const int MAX_OPTION_LEN= 1024; - -/* - The maximal length of whole option string: - --